rsvs3D  0.0.0
Codes for the c++ implementation of the 3D RSVS
tetgen.cpp
1 // //
3 // TetGen //
4 // //
5 // A Quality Tetrahedral Mesh Generator and A 3D Delaunay Triangulator //
6 // //
7 // Version 1.5 //
8 // August 18, 2018 //
9 // //
10 // Copyright (C) 2002--2018 //
11 // //
12 // TetGen is freely available through the website: http://www.tetgen.org. //
13 // It may be copied, modified, and redistributed for non-commercial use. //
14 // Please consult the file LICENSE for the detailed copyright notices. //
15 // //
17 
18 #include <iostream>
19 #include "tetgen.h"
20 
24 
26 // //
27 // load_node_call() Read a list of points from a file. //
28 // //
29 // 'infile' is the file handle contains the node list. It may point to a //
30 // .node, or .poly or .smesh file. 'markers' indicates each node contains an //
31 // additional marker (integer) or not. 'uvflag' indicates each node contains //
32 // u,v coordinates or not. It is reuqired by a PSC. 'infilename' is the name //
33 // of the file being read, it is only used in error messages. //
34 // //
35 // The 'firstnumber' (0 or 1) is automatically determined by the number of //
36 // the first index of the first point. //
37 // //
39 
40 bool tetgenio::load_node_call(FILE* infile, int markers, int uvflag,
41  char* infilename)
42 {
43  char inputline[INPUTLINESIZE];
44  char *stringptr;
45  REAL x, y, z, attrib;
46  int firstnode, currentmarker;
47  int index, attribindex;
48  int i, j;
49 
50  // Initialize 'pointlist', 'pointattributelist', and 'pointmarkerlist'.
51  pointlist = new REAL[numberofpoints * 3];
52  if (pointlist == (REAL *) NULL) {
53  terminatetetgen(NULL, 1);
54  }
55  if (numberofpointattributes > 0) {
56  pointattributelist = new REAL[numberofpoints * numberofpointattributes];
57  if (pointattributelist == (REAL *) NULL) {
58  terminatetetgen(NULL, 1);
59  }
60  }
61  if (markers) {
62  pointmarkerlist = new int[numberofpoints];
63  if (pointmarkerlist == (int *) NULL) {
64  terminatetetgen(NULL, 1);
65  }
66  }
67  if (uvflag) {
68  pointparamlist = new pointparam[numberofpoints];
69  if (pointparamlist == NULL) {
70  terminatetetgen(NULL, 1);
71  }
72  }
73 
74  // Read the point section.
75  index = 0;
76  attribindex = 0;
77  for (i = 0; i < numberofpoints; i++) {
78  stringptr = readnumberline(inputline, infile, infilename);
79  if (useindex) {
80  if (i == 0) {
81  firstnode = (int) strtol (stringptr, &stringptr, 0);
82  if ((firstnode == 0) || (firstnode == 1)) {
83  firstnumber = firstnode;
84  }
85  }
86  stringptr = findnextnumber(stringptr);
87  } // if (useindex)
88  if (*stringptr == '\0') {
89  printf("Error: Point %d has no x coordinate.\n", firstnumber + i);
90  break;
91  }
92  x = (REAL) strtod(stringptr, &stringptr);
93  stringptr = findnextnumber(stringptr);
94  if (*stringptr == '\0') {
95  printf("Error: Point %d has no y coordinate.\n", firstnumber + i);
96  break;
97  }
98  y = (REAL) strtod(stringptr, &stringptr);
99  if (mesh_dim == 3) {
100  stringptr = findnextnumber(stringptr);
101  if (*stringptr == '\0') {
102  printf("Error: Point %d has no z coordinate.\n", firstnumber + i);
103  break;
104  }
105  z = (REAL) strtod(stringptr, &stringptr);
106  } else {
107  z = 0.0; // mesh_dim == 2;
108  }
109  pointlist[index++] = x;
110  pointlist[index++] = y;
111  pointlist[index++] = z;
112  // Read the point attributes.
113  for (j = 0; j < numberofpointattributes; j++) {
114  stringptr = findnextnumber(stringptr);
115  if (*stringptr == '\0') {
116  attrib = 0.0;
117  } else {
118  attrib = (REAL) strtod(stringptr, &stringptr);
119  }
120  pointattributelist[attribindex++] = attrib;
121  }
122  if (markers) {
123  // Read a point marker.
124  stringptr = findnextnumber(stringptr);
125  if (*stringptr == '\0') {
126  currentmarker = 0;
127  } else {
128  currentmarker = (int) strtol (stringptr, &stringptr, 0);
129  }
130  pointmarkerlist[i] = currentmarker;
131  }
132  if (uvflag) {
133  // Read point paramteters.
134  stringptr = findnextnumber(stringptr);
135  if (*stringptr == '\0') {
136  printf("Error: Point %d has no uv[0].\n", firstnumber + i);
137  break;
138  }
139  pointparamlist[i].uv[0] = (REAL) strtod(stringptr, &stringptr);
140  stringptr = findnextnumber(stringptr);
141  if (*stringptr == '\0') {
142  printf("Error: Point %d has no uv[1].\n", firstnumber + i);
143  break;
144  }
145  pointparamlist[i].uv[1] = (REAL) strtod(stringptr, &stringptr);
146  stringptr = findnextnumber(stringptr);
147  if (*stringptr == '\0') {
148  printf("Error: Point %d has no tag.\n", firstnumber + i);
149  break;
150  }
151  pointparamlist[i].tag = (int) strtol (stringptr, &stringptr, 0);
152  stringptr = findnextnumber(stringptr);
153  if (*stringptr == '\0') {
154  printf("Error: Point %d has no type.\n", firstnumber + i);
155  break;
156  }
157  pointparamlist[i].type = (int) strtol (stringptr, &stringptr, 0);
158  if ((pointparamlist[i].type < 0) || (pointparamlist[i].type > 2)) {
159  printf("Error: Point %d has an invalid type.\n", firstnumber + i);
160  break;
161  }
162  }
163  }
164  if (i < numberofpoints) {
165  // Failed to read points due to some error.
166  delete [] pointlist;
167  pointlist = (REAL *) NULL;
168  if (markers) {
169  delete [] pointmarkerlist;
170  pointmarkerlist = (int *) NULL;
171  }
172  if (numberofpointattributes > 0) {
173  delete [] pointattributelist;
174  pointattributelist = (REAL *) NULL;
175  }
176  if (uvflag) {
177  delete [] pointparamlist;
178  pointparamlist = NULL;
179  }
180  numberofpoints = 0;
181  return false;
182  }
183  return true;
184 }
185 
187 // //
188 // load_node() Load a list of points from a .node file. //
189 // //
191 
192 bool tetgenio::load_node(const char* filebasename)
193 {
194  FILE *infile;
195  char innodefilename[FILENAMESIZE];
196  char inputline[INPUTLINESIZE];
197  char *stringptr;
198  bool okflag;
199  int markers;
200  int uvflag; // for psc input.
201 
202  // Assembling the actual file names we want to open.
203  strcpy(innodefilename, filebasename);
204  strcat(innodefilename, ".node");
205 
206  // Try to open a .node file.
207  infile = fopen(innodefilename, "r");
208  if (infile == (FILE *) NULL) {
209  printf(" Cannot access file %s.\n", innodefilename);
210  return false;
211  }
212  printf("Opening %s.\n", innodefilename);
213 
214  // Set initial flags.
215  mesh_dim = 3;
216  numberofpointattributes = 0; // no point attribute.
217  markers = 0; // no boundary marker.
218  uvflag = 0; // no uv parameters (required by a PSC).
219 
220  // Read the first line of the file.
221  stringptr = readnumberline(inputline, infile, innodefilename);
222  // Does this file contain an index column?
223  stringptr = strstr(inputline, "rbox");
224  if (stringptr == NULL) {
225  // Read number of points, number of dimensions, number of point
226  // attributes, and number of boundary markers.
227  stringptr = inputline;
228  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
229  stringptr = findnextnumber(stringptr);
230  if (*stringptr != '\0') {
231  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
232  }
233  stringptr = findnextnumber(stringptr);
234  if (*stringptr != '\0') {
235  numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
236  }
237  stringptr = findnextnumber(stringptr);
238  if (*stringptr != '\0') {
239  markers = (int) strtol (stringptr, &stringptr, 0);
240  }
241  stringptr = findnextnumber(stringptr);
242  if (*stringptr != '\0') {
243  uvflag = (int) strtol (stringptr, &stringptr, 0);
244  }
245  } else {
246  // It is a rbox (qhull) input file.
247  stringptr = inputline;
248  // Get the dimension.
249  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
250  // Get the number of points.
251  stringptr = readnumberline(inputline, infile, innodefilename);
252  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
253  // There is no index column.
254  useindex = 0;
255  }
256 
257  // Load the list of nodes.
258  okflag = load_node_call(infile, markers, uvflag, innodefilename);
259 
260  fclose(infile);
261  return okflag;
262 }
263 
265 // //
266 // load_edge() Load a list of edges from a .edge file. //
267 // //
269 
270 bool tetgenio::load_edge(const char* filebasename)
271 {
272  FILE *infile;
273  char inedgefilename[FILENAMESIZE];
274  char inputline[INPUTLINESIZE];
275  char *stringptr;
276  int markers, corner;
277  int index;
278  int i, j;
279 
280  strcpy(inedgefilename, filebasename);
281  strcat(inedgefilename, ".edge");
282 
283  infile = fopen(inedgefilename, "r");
284  if (infile != (FILE *) NULL) {
285  printf("Opening %s.\n", inedgefilename);
286  } else {
287  //printf(" Cannot access file %s.\n", inedgefilename);
288  return false;
289  }
290 
291  // Read number of boundary edges.
292  stringptr = readnumberline(inputline, infile, inedgefilename);
293  numberofedges = (int) strtol (stringptr, &stringptr, 0);
294  if (numberofedges > 0) {
295  edgelist = new int[numberofedges * 2];
296  if (edgelist == (int *) NULL) {
297  terminatetetgen(NULL, 1);
298  }
299  stringptr = findnextnumber(stringptr);
300  if (*stringptr == '\0') {
301  markers = 0; // Default value.
302  } else {
303  markers = (int) strtol (stringptr, &stringptr, 0);
304  }
305  if (markers > 0) {
306  edgemarkerlist = new int[numberofedges];
307  }
308  }
309 
310  // Read the list of edges.
311  index = 0;
312  for (i = 0; i < numberofedges; i++) {
313  // Read edge index and the edge's two endpoints.
314  stringptr = readnumberline(inputline, infile, inedgefilename);
315  for (j = 0; j < 2; j++) {
316  stringptr = findnextnumber(stringptr);
317  if (*stringptr == '\0') {
318  printf("Error: Edge %d is missing vertex %d in %s.\n",
319  i + firstnumber, j + 1, inedgefilename);
320  terminatetetgen(NULL, 1);
321  }
322  corner = (int) strtol(stringptr, &stringptr, 0);
323  if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
324  printf("Error: Edge %d has an invalid vertex index.\n",
325  i + firstnumber);
326  terminatetetgen(NULL, 1);
327  }
328  edgelist[index++] = corner;
329  }
330  if (numberofcorners == 10) {
331  // Skip an extra vertex (generated by a previous -o2 option).
332  stringptr = findnextnumber(stringptr);
333  }
334  // Read the edge marker if it has.
335  if (markers) {
336  stringptr = findnextnumber(stringptr);
337  edgemarkerlist[i] = (int) strtol(stringptr, &stringptr, 0);
338  }
339  }
340 
341  fclose(infile);
342  return true;
343 }
344 
346 // //
347 // load_face() Load a list of faces (triangles) from a .face file. //
348 // //
350 
351 bool tetgenio::load_face(const char* filebasename)
352 {
353  FILE *infile;
354  char infilename[FILENAMESIZE];
355  char inputline[INPUTLINESIZE];
356  char *stringptr;
357  REAL attrib;
358  int markers, corner;
359  int index;
360  int i, j;
361 
362  strcpy(infilename, filebasename);
363  strcat(infilename, ".face");
364 
365  infile = fopen(infilename, "r");
366  if (infile != (FILE *) NULL) {
367  printf("Opening %s.\n", infilename);
368  } else {
369  return false;
370  }
371 
372  // Read number of faces, boundary markers.
373  stringptr = readnumberline(inputline, infile, infilename);
374  numberoftrifaces = (int) strtol (stringptr, &stringptr, 0);
375  stringptr = findnextnumber(stringptr);
376  if (mesh_dim == 2) {
377  // Skip a number.
378  stringptr = findnextnumber(stringptr);
379  }
380  if (*stringptr == '\0') {
381  markers = 0; // Default there is no marker per face.
382  } else {
383  markers = (int) strtol (stringptr, &stringptr, 0);
384  }
385  if (numberoftrifaces > 0) {
386  trifacelist = new int[numberoftrifaces * 3];
387  if (trifacelist == (int *) NULL) {
388  terminatetetgen(NULL, 1);
389  }
390  if (markers) {
391  trifacemarkerlist = new int[numberoftrifaces];
392  if (trifacemarkerlist == (int *) NULL) {
393  terminatetetgen(NULL, 1);
394  }
395  }
396  }
397 
398  // Read the list of faces.
399  index = 0;
400  for (i = 0; i < numberoftrifaces; i++) {
401  // Read face index and the face's three corners.
402  stringptr = readnumberline(inputline, infile, infilename);
403  for (j = 0; j < 3; j++) {
404  stringptr = findnextnumber(stringptr);
405  if (*stringptr == '\0') {
406  printf("Error: Face %d is missing vertex %d in %s.\n",
407  i + firstnumber, j + 1, infilename);
408  terminatetetgen(NULL, 1);
409  }
410  corner = (int) strtol(stringptr, &stringptr, 0);
411  if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
412  printf("Error: Face %d has an invalid vertex index.\n",
413  i + firstnumber);
414  terminatetetgen(NULL, 1);
415  }
416  trifacelist[index++] = corner;
417  }
418  if (numberofcorners == 10) {
419  // Skip 3 extra vertices (generated by a previous -o2 option).
420  for (j = 0; j < 3; j++) {
421  stringptr = findnextnumber(stringptr);
422  }
423  }
424  // Read the boundary marker if it exists.
425  if (markers) {
426  stringptr = findnextnumber(stringptr);
427  if (*stringptr == '\0') {
428  attrib = 0.0;
429  } else {
430  attrib = (REAL) strtod(stringptr, &stringptr);
431  }
432  trifacemarkerlist[i] = (int) attrib;
433  }
434  }
435 
436  fclose(infile);
437 
438  return true;
439 }
440 
442 // //
443 // load_tet() Load a list of tetrahedra from a .ele file. //
444 // //
446 
447 bool tetgenio::load_tet(const char* filebasename)
448 {
449  FILE *infile;
450  char infilename[FILENAMESIZE];
451  char inputline[INPUTLINESIZE];
452  char *stringptr;
453  REAL attrib;
454  int corner;
455  int index, attribindex;
456  int i, j;
457 
458  strcpy(infilename, filebasename);
459  strcat(infilename, ".ele");
460 
461  infile = fopen(infilename, "r");
462  if (infile != (FILE *) NULL) {
463  printf("Opening %s.\n", infilename);
464  } else {
465  return false;
466  }
467 
468  // Read number of elements, number of corners (4 or 10), number of
469  // element attributes.
470  stringptr = readnumberline(inputline, infile, infilename);
471  numberoftetrahedra = (int) strtol (stringptr, &stringptr, 0);
472  if (numberoftetrahedra <= 0) {
473  printf("Error: Invalid number of tetrahedra.\n");
474  fclose(infile);
475  return false;
476  }
477  stringptr = findnextnumber(stringptr);
478  if (*stringptr == '\0') {
479  numberofcorners = 4; // Default read 4 nodes per element.
480  } else {
481  numberofcorners = (int) strtol(stringptr, &stringptr, 0);
482  }
483  stringptr = findnextnumber(stringptr);
484  if (*stringptr == '\0') {
485  numberoftetrahedronattributes = 0; // Default no attribute.
486  } else {
487  numberoftetrahedronattributes = (int) strtol(stringptr, &stringptr, 0);
488  }
489  if (numberofcorners != 4 && numberofcorners != 10) {
490  printf("Error: Wrong number of corners %d (should be 4 or 10).\n",
491  numberofcorners);
492  fclose(infile);
493  return false;
494  }
495 
496  // Allocate memory for tetrahedra.
497  tetrahedronlist = new int[numberoftetrahedra * numberofcorners];
498  if (tetrahedronlist == (int *) NULL) {
499  terminatetetgen(NULL, 1);
500  }
501  // Allocate memory for output tetrahedron attributes if necessary.
502  if (numberoftetrahedronattributes > 0) {
503  tetrahedronattributelist = new REAL[numberoftetrahedra *
504  numberoftetrahedronattributes];
505  if (tetrahedronattributelist == (REAL *) NULL) {
506  terminatetetgen(NULL, 1);
507  }
508  }
509 
510  // Read the list of tetrahedra.
511  index = 0;
512  attribindex = 0;
513  for (i = 0; i < numberoftetrahedra; i++) {
514  // Read tetrahedron index and the tetrahedron's corners.
515  stringptr = readnumberline(inputline, infile, infilename);
516  for (j = 0; j < numberofcorners; j++) {
517  stringptr = findnextnumber(stringptr);
518  if (*stringptr == '\0') {
519  printf("Error: Tetrahedron %d is missing vertex %d in %s.\n",
520  i + firstnumber, j + 1, infilename);
521  terminatetetgen(NULL, 1);
522  }
523  corner = (int) strtol(stringptr, &stringptr, 0);
524  if (corner < firstnumber || corner >= numberofpoints + firstnumber) {
525  printf("Error: Tetrahedron %d has an invalid vertex index.\n",
526  i + firstnumber);
527  terminatetetgen(NULL, 1);
528  }
529  tetrahedronlist[index++] = corner;
530  }
531  // Read the tetrahedron's attributes.
532  for (j = 0; j < numberoftetrahedronattributes; j++) {
533  stringptr = findnextnumber(stringptr);
534  if (*stringptr == '\0') {
535  attrib = 0.0;
536  } else {
537  attrib = (REAL) strtod(stringptr, &stringptr);
538  }
539  tetrahedronattributelist[attribindex++] = attrib;
540  }
541  }
542 
543  fclose(infile);
544 
545  return true;
546 }
547 
549 // //
550 // load_vol() Load a list of volume constraints from a .vol file. //
551 // //
553 
554 bool tetgenio::load_vol(const char* filebasename)
555 {
556  FILE *infile;
557  char inelefilename[FILENAMESIZE];
558  char infilename[FILENAMESIZE];
559  char inputline[INPUTLINESIZE];
560  char *stringptr;
561  REAL volume;
562  int volelements;
563  int i;
564 
565  strcpy(infilename, filebasename);
566  strcat(infilename, ".vol");
567 
568  infile = fopen(infilename, "r");
569  if (infile != (FILE *) NULL) {
570  printf("Opening %s.\n", infilename);
571  } else {
572  return false;
573  }
574 
575  // Read number of tetrahedra.
576  stringptr = readnumberline(inputline, infile, infilename);
577  volelements = (int) strtol (stringptr, &stringptr, 0);
578  if (volelements != numberoftetrahedra) {
579  strcpy(inelefilename, filebasename);
580  strcat(infilename, ".ele");
581  printf("Warning: %s and %s disagree on number of tetrahedra.\n",
582  inelefilename, infilename);
583  fclose(infile);
584  return false;
585  }
586 
587  tetrahedronvolumelist = new REAL[volelements];
588  if (tetrahedronvolumelist == (REAL *) NULL) {
589  terminatetetgen(NULL, 1);
590  }
591 
592  // Read the list of volume constraints.
593  for (i = 0; i < volelements; i++) {
594  stringptr = readnumberline(inputline, infile, infilename);
595  stringptr = findnextnumber(stringptr);
596  if (*stringptr == '\0') {
597  volume = -1.0; // No constraint on this tetrahedron.
598  } else {
599  volume = (REAL) strtod(stringptr, &stringptr);
600  }
601  tetrahedronvolumelist[i] = volume;
602  }
603 
604  fclose(infile);
605 
606  return true;
607 }
608 
610 // //
611 // load_var() Load constraints applied on facets, segments, and nodes //
612 // from a .var file. //
613 // //
615 
616 bool tetgenio::load_var(const char* filebasename)
617 {
618  FILE *infile;
619  char varfilename[FILENAMESIZE];
620  char inputline[INPUTLINESIZE];
621  char *stringptr;
622  int index;
623  int i;
624 
625  // Variant constraints are saved in file "filename.var".
626  strcpy(varfilename, filebasename);
627  strcat(varfilename, ".var");
628  infile = fopen(varfilename, "r");
629  if (infile != (FILE *) NULL) {
630  printf("Opening %s.\n", varfilename);
631  } else {
632  return false;
633  }
634 
635  // Read the facet constraint section.
636  stringptr = readnumberline(inputline, infile, varfilename);
637  if (stringptr == NULL) {
638  // No region list, return.
639  fclose(infile);
640  return true;
641  }
642  if (*stringptr != '\0') {
643  numberoffacetconstraints = (int) strtol (stringptr, &stringptr, 0);
644  } else {
645  numberoffacetconstraints = 0;
646  }
647  if (numberoffacetconstraints > 0) {
648  // Initialize 'facetconstraintlist'.
649  facetconstraintlist = new REAL[numberoffacetconstraints * 2];
650  index = 0;
651  for (i = 0; i < numberoffacetconstraints; i++) {
652  stringptr = readnumberline(inputline, infile, varfilename);
653  stringptr = findnextnumber(stringptr);
654  if (*stringptr == '\0') {
655  printf("Error: facet constraint %d has no facet marker.\n",
656  firstnumber + i);
657  break;
658  } else {
659  facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
660  }
661  stringptr = findnextnumber(stringptr);
662  if (*stringptr == '\0') {
663  printf("Error: facet constraint %d has no maximum area bound.\n",
664  firstnumber + i);
665  break;
666  } else {
667  facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
668  }
669  }
670  if (i < numberoffacetconstraints) {
671  // This must be caused by an error.
672  fclose(infile);
673  return false;
674  }
675  }
676 
677  // Read the segment constraint section.
678  stringptr = readnumberline(inputline, infile, varfilename);
679  if (stringptr == NULL) {
680  // No segment list, return.
681  fclose(infile);
682  return true;
683  }
684  if (*stringptr != '\0') {
685  numberofsegmentconstraints = (int) strtol (stringptr, &stringptr, 0);
686  } else {
687  numberofsegmentconstraints = 0;
688  }
689  if (numberofsegmentconstraints > 0) {
690  // Initialize 'segmentconstraintlist'.
691  segmentconstraintlist = new REAL[numberofsegmentconstraints * 3];
692  index = 0;
693  for (i = 0; i < numberofsegmentconstraints; i++) {
694  stringptr = readnumberline(inputline, infile, varfilename);
695  stringptr = findnextnumber(stringptr);
696  if (*stringptr == '\0') {
697  printf("Error: segment constraint %d has no frist endpoint.\n",
698  firstnumber + i);
699  break;
700  } else {
701  segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
702  }
703  stringptr = findnextnumber(stringptr);
704  if (*stringptr == '\0') {
705  printf("Error: segment constraint %d has no second endpoint.\n",
706  firstnumber + i);
707  break;
708  } else {
709  segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
710  }
711  stringptr = findnextnumber(stringptr);
712  if (*stringptr == '\0') {
713  printf("Error: segment constraint %d has no maximum length bound.\n",
714  firstnumber + i);
715  break;
716  } else {
717  segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr);
718  }
719  }
720  if (i < numberofsegmentconstraints) {
721  // This must be caused by an error.
722  fclose(infile);
723  return false;
724  }
725  }
726 
727  fclose(infile);
728  return true;
729 }
730 
732 // //
733 // load_mtr() Load a size specification map from a .mtr file. //
734 // //
736 
737 bool tetgenio::load_mtr(const char* filebasename)
738 {
739  FILE *infile;
740  char mtrfilename[FILENAMESIZE];
741  char inputline[INPUTLINESIZE];
742  char *stringptr;
743  REAL mtr;
744  int ptnum;
745  int mtrindex;
746  int i, j;
747 
748  strcpy(mtrfilename, filebasename);
749  strcat(mtrfilename, ".mtr");
750  infile = fopen(mtrfilename, "r");
751  if (infile != (FILE *) NULL) {
752  printf("Opening %s.\n", mtrfilename);
753  } else {
754  return false;
755  }
756 
757  // Read the number of points.
758  stringptr = readnumberline(inputline, infile, mtrfilename);
759  ptnum = (int) strtol (stringptr, &stringptr, 0);
760  if (ptnum != numberofpoints) {
761  printf(" !! Point numbers are not equal. Ignored.\n");
762  fclose(infile);
763  return false;
764  }
765  // Read the number of columns (1, 3, or 6).
766  stringptr = findnextnumber(stringptr); // Skip number of points.
767  if (*stringptr != '\0') {
768  numberofpointmtrs = (int) strtol (stringptr, &stringptr, 0);
769  }
770  if ((numberofpointmtrs != 1) && (numberofpointmtrs != 3) &&
771  (numberofpointmtrs != 6)) {
772  // Column number doesn't match.
773  numberofpointmtrs = 0;
774  printf(" !! Metric size does not match (1, 3, or 6). Ignored.\n");
775  fclose(infile);
776  return false;
777  }
778 
779  // Allocate space for pointmtrlist.
780  pointmtrlist = new REAL[numberofpoints * numberofpointmtrs];
781  if (pointmtrlist == (REAL *) NULL) {
782  terminatetetgen(NULL, 1);
783  }
784  mtrindex = 0;
785  for (i = 0; i < numberofpoints; i++) {
786  // Read metrics.
787  stringptr = readnumberline(inputline, infile, mtrfilename);
788  for (j = 0; j < numberofpointmtrs; j++) {
789  if (*stringptr == '\0') {
790  printf("Error: Metric %d is missing value #%d in %s.\n",
791  i + firstnumber, j + 1, mtrfilename);
792  terminatetetgen(NULL, 1);
793  }
794  mtr = (REAL) strtod(stringptr, &stringptr);
795  pointmtrlist[mtrindex++] = mtr;
796  stringptr = findnextnumber(stringptr);
797  }
798  }
799 
800  fclose(infile);
801  return true;
802 }
803 
805 // //
806 // load_poly() Load a PL complex from a .poly or a .smesh file. //
807 // //
809 
810 bool tetgenio::load_poly(const char* filebasename)
811 {
812  FILE *infile;
813  char inpolyfilename[FILENAMESIZE];
814  char insmeshfilename[FILENAMESIZE];
815  char inputline[INPUTLINESIZE];
816  char *stringptr, *infilename;
817  int smesh, markers, uvflag, currentmarker;
818  int index;
819  int i, j, k;
820 
821  // Assembling the actual file names we want to open.
822  strcpy(inpolyfilename, filebasename);
823  strcpy(insmeshfilename, filebasename);
824  strcat(inpolyfilename, ".poly");
825  strcat(insmeshfilename, ".smesh");
826 
827  // First assume it is a .poly file.
828  smesh = 0;
829  // Try to open a .poly file.
830  infile = fopen(inpolyfilename, "r");
831  if (infile == (FILE *) NULL) {
832  // .poly doesn't exist! Try to open a .smesh file.
833  infile = fopen(insmeshfilename, "r");
834  if (infile == (FILE *) NULL) {
835  printf(" Cannot access file %s and %s.\n",
836  inpolyfilename, insmeshfilename);
837  return false;
838  } else {
839  printf("Opening %s.\n", insmeshfilename);
840  infilename = insmeshfilename;
841  }
842  smesh = 1;
843  } else {
844  printf("Opening %s.\n", inpolyfilename);
845  infilename = inpolyfilename;
846  }
847 
848  // Initialize the default values.
849  mesh_dim = 3; // Three-dimensional coordinates.
850  numberofpointattributes = 0; // no point attribute.
851  markers = 0; // no boundary marker.
852  uvflag = 0; // no uv parameters (required by a PSC).
853 
854  // Read number of points, number of dimensions, number of point
855  // attributes, and number of boundary markers.
856  stringptr = readnumberline(inputline, infile, infilename);
857  numberofpoints = (int) strtol (stringptr, &stringptr, 0);
858  stringptr = findnextnumber(stringptr);
859  if (*stringptr != '\0') {
860  mesh_dim = (int) strtol (stringptr, &stringptr, 0);
861  }
862  stringptr = findnextnumber(stringptr);
863  if (*stringptr != '\0') {
864  numberofpointattributes = (int) strtol (stringptr, &stringptr, 0);
865  }
866  stringptr = findnextnumber(stringptr);
867  if (*stringptr != '\0') {
868  markers = (int) strtol (stringptr, &stringptr, 0);
869  }
870  if (*stringptr != '\0') {
871  uvflag = (int) strtol (stringptr, &stringptr, 0);
872  }
873 
874  if (numberofpoints > 0) {
875  // Load the list of nodes.
876  if (!load_node_call(infile, markers, uvflag, infilename)) {
877  fclose(infile);
878  return false;
879  }
880  } else {
881  // If the .poly or .smesh file claims there are zero points, that
882  // means the points should be read from a separate .node file.
883  if (!load_node(filebasename)) {
884  fclose(infile);
885  return false;
886  }
887  }
888 
889  if ((mesh_dim != 3) && (mesh_dim != 2)) {
890  printf("Input error: TetGen only works for 2D & 3D point sets.\n");
891  fclose(infile);
892  return false;
893  }
894  if (numberofpoints < (mesh_dim + 1)) {
895  printf("Input error: TetGen needs at least %d points.\n", mesh_dim + 1);
896  fclose(infile);
897  return false;
898  }
899 
900  facet *f;
901  polygon *p;
902 
903  if (mesh_dim == 3) {
904 
905  // Read number of facets and number of boundary markers.
906  stringptr = readnumberline(inputline, infile, infilename);
907  if (stringptr == NULL) {
908  // No facet list, return.
909  fclose(infile);
910  return true;
911  }
912  numberoffacets = (int) strtol (stringptr, &stringptr, 0);
913  if (numberoffacets <= 0) {
914  // No facet list, return.
915  fclose(infile);
916  return true;
917  }
918  stringptr = findnextnumber(stringptr);
919  if (*stringptr == '\0') {
920  markers = 0; // no boundary marker.
921  } else {
922  markers = (int) strtol (stringptr, &stringptr, 0);
923  }
924 
925  // Initialize the 'facetlist', 'facetmarkerlist'.
926  facetlist = new facet[numberoffacets];
927  if (markers == 1) {
928  facetmarkerlist = new int[numberoffacets];
929  }
930 
931  // Read data into 'facetlist', 'facetmarkerlist'.
932  if (smesh == 0) {
933  // Facets are in .poly file format.
934  for (i = 1; i <= numberoffacets; i++) {
935  f = &(facetlist[i - 1]);
936  init(f);
937  f->numberofholes = 0;
938  currentmarker = 0;
939  // Read number of polygons, number of holes, and a boundary marker.
940  stringptr = readnumberline(inputline, infile, infilename);
941  f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0);
942  stringptr = findnextnumber(stringptr);
943  if (*stringptr != '\0') {
944  f->numberofholes = (int) strtol (stringptr, &stringptr, 0);
945  if (markers == 1) {
946  stringptr = findnextnumber(stringptr);
947  if (*stringptr != '\0') {
948  currentmarker = (int) strtol(stringptr, &stringptr, 0);
949  }
950  }
951  }
952  // Initialize facetmarker if it needs.
953  if (markers == 1) {
954  facetmarkerlist[i - 1] = currentmarker;
955  }
956  // Each facet should has at least one polygon.
957  if (f->numberofpolygons <= 0) {
958  printf("Error: Wrong number of polygon in %d facet.\n", i);
959  break;
960  }
961  // Initialize the 'f->polygonlist'.
962  f->polygonlist = new polygon[f->numberofpolygons];
963  // Go through all polygons, read in their vertices.
964  for (j = 1; j <= f->numberofpolygons; j++) {
965  p = &(f->polygonlist[j - 1]);
966  init(p);
967  // Read number of vertices of this polygon.
968  stringptr = readnumberline(inputline, infile, infilename);
969  p->numberofvertices = (int) strtol(stringptr, &stringptr, 0);
970  if (p->numberofvertices < 1) {
971  printf("Error: Wrong polygon %d in facet %d\n", j, i);
972  break;
973  }
974  // Initialize 'p->vertexlist'.
975  p->vertexlist = new int[p->numberofvertices];
976  // Read all vertices of this polygon.
977  for (k = 1; k <= p->numberofvertices; k++) {
978  stringptr = findnextnumber(stringptr);
979  if (*stringptr == '\0') {
980  // Try to load another non-empty line and continue to read the
981  // rest of vertices.
982  stringptr = readnumberline(inputline, infile, infilename);
983  if (*stringptr == '\0') {
984  printf("Error: Missing %d endpoints of polygon %d in facet %d",
985  p->numberofvertices - k, j, i);
986  break;
987  }
988  }
989  p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
990  }
991  }
992  if (j <= f->numberofpolygons) {
993  // This must be caused by an error. However, there're j - 1
994  // polygons have been read. Reset the 'f->numberofpolygon'.
995  if (j == 1) {
996  // This is the first polygon.
997  delete [] f->polygonlist;
998  }
999  f->numberofpolygons = j - 1;
1000  // No hole will be read even it exists.
1001  f->numberofholes = 0;
1002  break;
1003  }
1004  // If this facet has hole pints defined, read them.
1005  if (f->numberofholes > 0) {
1006  // Initialize 'f->holelist'.
1007  f->holelist = new REAL[f->numberofholes * 3];
1008  // Read the holes' coordinates.
1009  index = 0;
1010  for (j = 1; j <= f->numberofholes; j++) {
1011  stringptr = readnumberline(inputline, infile, infilename);
1012  for (k = 1; k <= 3; k++) {
1013  stringptr = findnextnumber(stringptr);
1014  if (*stringptr == '\0') {
1015  printf("Error: Hole %d in facet %d has no coordinates", j, i);
1016  break;
1017  }
1018  f->holelist[index++] = (REAL) strtod (stringptr, &stringptr);
1019  }
1020  if (k <= 3) {
1021  // This must be caused by an error.
1022  break;
1023  }
1024  }
1025  if (j <= f->numberofholes) {
1026  // This must be caused by an error.
1027  break;
1028  }
1029  }
1030  }
1031  if (i <= numberoffacets) {
1032  // This must be caused by an error.
1033  numberoffacets = i - 1;
1034  fclose(infile);
1035  return false;
1036  }
1037  } else { // poly == 0
1038  // Read the facets from a .smesh file.
1039  for (i = 1; i <= numberoffacets; i++) {
1040  f = &(facetlist[i - 1]);
1041  init(f);
1042  // Initialize 'f->facetlist'. In a .smesh file, each facetlist only
1043  // contains exactly one polygon, no hole.
1044  f->numberofpolygons = 1;
1045  f->polygonlist = new polygon[f->numberofpolygons];
1046  p = &(f->polygonlist[0]);
1047  init(p);
1048  // Read number of vertices of this polygon.
1049  stringptr = readnumberline(inputline, infile, insmeshfilename);
1050  p->numberofvertices = (int) strtol (stringptr, &stringptr, 0);
1051  if (p->numberofvertices < 1) {
1052  printf("Error: Wrong number of vertex in facet %d\n", i);
1053  break;
1054  }
1055  // Initialize 'p->vertexlist'.
1056  p->vertexlist = new int[p->numberofvertices];
1057  for (k = 1; k <= p->numberofvertices; k++) {
1058  stringptr = findnextnumber(stringptr);
1059  if (*stringptr == '\0') {
1060  // Try to load another non-empty line and continue to read the
1061  // rest of vertices.
1062  stringptr = readnumberline(inputline, infile, infilename);
1063  if (*stringptr == '\0') {
1064  printf("Error: Missing %d endpoints in facet %d",
1065  p->numberofvertices - k, i);
1066  break;
1067  }
1068  }
1069  p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0);
1070  }
1071  if (k <= p->numberofvertices) {
1072  // This must be caused by an error.
1073  break;
1074  }
1075  // Read facet's boundary marker at last.
1076  if (markers == 1) {
1077  stringptr = findnextnumber(stringptr);
1078  if (*stringptr == '\0') {
1079  currentmarker = 0;
1080  } else {
1081  currentmarker = (int) strtol(stringptr, &stringptr, 0);
1082  }
1083  facetmarkerlist[i - 1] = currentmarker;
1084  }
1085  }
1086  if (i <= numberoffacets) {
1087  // This must be caused by an error.
1088  numberoffacets = i - 1;
1089  fclose(infile);
1090  return false;
1091  }
1092  }
1093 
1094  // Read the hole section.
1095  stringptr = readnumberline(inputline, infile, infilename);
1096  if (stringptr == NULL) {
1097  // No hole list, return.
1098  fclose(infile);
1099  return true;
1100  }
1101  if (*stringptr != '\0') {
1102  numberofholes = (int) strtol (stringptr, &stringptr, 0);
1103  } else {
1104  numberofholes = 0;
1105  }
1106  if (numberofholes > 0) {
1107  // Initialize 'holelist'.
1108  holelist = new REAL[numberofholes * 3];
1109  for (i = 0; i < 3 * numberofholes; i += 3) {
1110  stringptr = readnumberline(inputline, infile, infilename);
1111  stringptr = findnextnumber(stringptr);
1112  if (*stringptr == '\0') {
1113  printf("Error: Hole %d has no x coord.\n", firstnumber + (i / 3));
1114  break;
1115  } else {
1116  holelist[i] = (REAL) strtod(stringptr, &stringptr);
1117  }
1118  stringptr = findnextnumber(stringptr);
1119  if (*stringptr == '\0') {
1120  printf("Error: Hole %d has no y coord.\n", firstnumber + (i / 3));
1121  break;
1122  } else {
1123  holelist[i + 1] = (REAL) strtod(stringptr, &stringptr);
1124  }
1125  stringptr = findnextnumber(stringptr);
1126  if (*stringptr == '\0') {
1127  printf("Error: Hole %d has no z coord.\n", firstnumber + (i / 3));
1128  break;
1129  } else {
1130  holelist[i + 2] = (REAL) strtod(stringptr, &stringptr);
1131  }
1132  }
1133  if (i < 3 * numberofholes) {
1134  // This must be caused by an error.
1135  fclose(infile);
1136  return false;
1137  }
1138  }
1139 
1140  // Read the region section. The 'region' section is optional, if we
1141  // don't reach the end-of-file, try read it in.
1142  stringptr = readnumberline(inputline, infile, NULL);
1143  if (stringptr != (char *) NULL && *stringptr != '\0') {
1144  numberofregions = (int) strtol (stringptr, &stringptr, 0);
1145  } else {
1146  numberofregions = 0;
1147  }
1148  if (numberofregions > 0) {
1149  // Initialize 'regionlist'.
1150  regionlist = new REAL[numberofregions * 5];
1151  index = 0;
1152  for (i = 0; i < numberofregions; i++) {
1153  stringptr = readnumberline(inputline, infile, infilename);
1154  stringptr = findnextnumber(stringptr);
1155  if (*stringptr == '\0') {
1156  printf("Error: Region %d has no x coordinate.\n", firstnumber + i);
1157  break;
1158  } else {
1159  regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1160  }
1161  stringptr = findnextnumber(stringptr);
1162  if (*stringptr == '\0') {
1163  printf("Error: Region %d has no y coordinate.\n", firstnumber + i);
1164  break;
1165  } else {
1166  regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1167  }
1168  stringptr = findnextnumber(stringptr);
1169  if (*stringptr == '\0') {
1170  printf("Error: Region %d has no z coordinate.\n", firstnumber + i);
1171  break;
1172  } else {
1173  regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1174  }
1175  stringptr = findnextnumber(stringptr);
1176  if (*stringptr == '\0') {
1177  printf("Error: Region %d has no region attrib.\n", firstnumber + i);
1178  break;
1179  } else {
1180  regionlist[index++] = (REAL) strtod(stringptr, &stringptr);
1181  }
1182  stringptr = findnextnumber(stringptr);
1183  if (*stringptr == '\0') {
1184  regionlist[index] = regionlist[index - 1];
1185  } else {
1186  regionlist[index] = (REAL) strtod(stringptr, &stringptr);
1187  }
1188  index++;
1189  }
1190  if (i < numberofregions) {
1191  // This must be caused by an error.
1192  fclose(infile);
1193  return false;
1194  }
1195  }
1196 
1197  }
1198 
1199  // End of reading poly/smesh file.
1200  fclose(infile);
1201  return true;
1202 }
1203 
1205 // //
1206 // load_off() Load a polyhedron from a .off file. //
1207 // //
1208 // The .off format is one of file formats of the Geomview, an interactive //
1209 // program for viewing and manipulating geometric objects. More information //
1210 // is available form: http://www.geomview.org. //
1211 // //
1213 
1214 bool tetgenio::load_off(const char* filebasename)
1215 {
1216  FILE *fp;
1217  tetgenio::facet *f;
1218  tetgenio::polygon *p;
1219  char infilename[FILENAMESIZE];
1220  char buffer[INPUTLINESIZE];
1221  char *bufferp;
1222  double *coord;
1223  int nverts = 0, iverts = 0;
1224  int nfaces = 0, ifaces = 0;
1225  int nedges = 0;
1226  int line_count = 0, i;
1227 
1228  // Default, the off file's index is from '0'. We check it by remembering the
1229  // smallest index we found in the file. It should be either 0 or 1.
1230  int smallestidx = 0;
1231 
1232  strncpy(infilename, filebasename, 1024 - 1);
1233  infilename[FILENAMESIZE - 1] = '\0';
1234  if (infilename[0] == '\0') {
1235  printf("Error: No filename.\n");
1236  return false;
1237  }
1238  if (strcmp(&infilename[strlen(infilename) - 4], ".off") != 0) {
1239  strcat(infilename, ".off");
1240  }
1241 
1242  if (!(fp = fopen(infilename, "r"))) {
1243  printf(" Unable to open file %s\n", infilename);
1244  return false;
1245  }
1246  printf("Opening %s.\n", infilename);
1247 
1248  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1249  // Check section
1250  if (nverts == 0) {
1251  // Read header
1252  bufferp = strstr(bufferp, "OFF");
1253  if (bufferp != NULL) {
1254  // Read mesh counts
1255  bufferp = findnextnumber(bufferp); // Skip field "OFF".
1256  if (*bufferp == '\0') {
1257  // Read a non-empty line.
1258  bufferp = readline(buffer, fp, &line_count);
1259  }
1260  if ((sscanf(bufferp, "%d%d%d", &nverts, &nfaces, &nedges) != 3)
1261  || (nverts == 0)) {
1262  printf("Syntax error reading header on line %d in file %s\n",
1263  line_count, infilename);
1264  fclose(fp);
1265  return false;
1266  }
1267  // Allocate memory for 'tetgenio'
1268  if (nverts > 0) {
1269  numberofpoints = nverts;
1270  pointlist = new REAL[nverts * 3];
1271  smallestidx = nverts + 1; // A bigger enough number.
1272  }
1273  if (nfaces > 0) {
1274  numberoffacets = nfaces;
1275  facetlist = new tetgenio::facet[nfaces];
1276  }
1277  }
1278  } else if (iverts < nverts) {
1279  // Read vertex coordinates
1280  coord = &pointlist[iverts * 3];
1281  for (i = 0; i < 3; i++) {
1282  if (*bufferp == '\0') {
1283  printf("Syntax error reading vertex coords on line %d in file %s\n",
1284  line_count, infilename);
1285  fclose(fp);
1286  return false;
1287  }
1288  coord[i] = (REAL) strtod(bufferp, &bufferp);
1289  bufferp = findnextnumber(bufferp);
1290  }
1291  iverts++;
1292  } else if (ifaces < nfaces) {
1293  // Get next face
1294  f = &facetlist[ifaces];
1295  init(f);
1296  // In .off format, each facet has one polygon, no hole.
1297  f->numberofpolygons = 1;
1298  f->polygonlist = new tetgenio::polygon[1];
1299  p = &f->polygonlist[0];
1300  init(p);
1301  // Read the number of vertices, it should be greater than 0.
1302  p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
1303  if (p->numberofvertices == 0) {
1304  printf("Syntax error reading polygon on line %d in file %s\n",
1305  line_count, infilename);
1306  fclose(fp);
1307  return false;
1308  }
1309  // Allocate memory for face vertices
1310  p->vertexlist = new int[p->numberofvertices];
1311  for (i = 0; i < p->numberofvertices; i++) {
1312  bufferp = findnextnumber(bufferp);
1313  if (*bufferp == '\0') {
1314  printf("Syntax error reading polygon on line %d in file %s\n",
1315  line_count, infilename);
1316  fclose(fp);
1317  return false;
1318  }
1319  p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
1320  // Detect the smallest index.
1321  if (p->vertexlist[i] < smallestidx) {
1322  smallestidx = p->vertexlist[i];
1323  }
1324  }
1325  ifaces++;
1326  } else {
1327  // Should never get here
1328  printf("Found extra text starting at line %d in file %s\n", line_count,
1329  infilename);
1330  break;
1331  }
1332  }
1333 
1334  // Close file
1335  fclose(fp);
1336 
1337  // Decide the firstnumber of the index.
1338  if (smallestidx == 0) {
1339  firstnumber = 0;
1340  } else if (smallestidx == 1) {
1341  firstnumber = 1;
1342  } else {
1343  printf("A wrong smallest index (%d) was detected in file %s\n",
1344  smallestidx, infilename);
1345  return false;
1346  }
1347 
1348  if (iverts != nverts) {
1349  printf("Expected %d vertices, but read only %d vertices in file %s\n",
1350  nverts, iverts, infilename);
1351  return false;
1352  }
1353  if (ifaces != nfaces) {
1354  printf("Expected %d faces, but read only %d faces in file %s\n",
1355  nfaces, ifaces, infilename);
1356  return false;
1357  }
1358 
1359  return true;
1360 }
1361 
1363 // //
1364 // load_ply() Load a polyhedron from a .ply file. //
1365 // //
1366 // This is a simplified version of reading .ply files, which only reads the //
1367 // set of vertices and the set of faces. Other informations (such as color, //
1368 // material, texture, etc) in .ply file are ignored. Complete routines for //
1369 // reading and writing ,ply files are available from: http://www.cc.gatech. //
1370 // edu/projects/large_models/ply.html. Except the header section, ply file //
1371 // format has exactly the same format for listing vertices and polygons as //
1372 // off file format. //
1373 // //
1375 
1376 bool tetgenio::load_ply(const char* filebasename)
1377 {
1378  FILE *fp;
1379  tetgenio::facet *f;
1380  tetgenio::polygon *p;
1381  char infilename[FILENAMESIZE];
1382  char buffer[INPUTLINESIZE];
1383  char *bufferp, *str;
1384  double *coord;
1385  int endheader = 0, format = 0;
1386  int nverts = 0, iverts = 0;
1387  int nfaces = 0, ifaces = 0;
1388  int line_count = 0, i;
1389 
1390  // Default, the ply file's index is from '0'. We check it by remembering the
1391  // smallest index we found in the file. It should be either 0 or 1.
1392  int smallestidx = 0;
1393 
1394  strncpy(infilename, filebasename, FILENAMESIZE - 1);
1395  infilename[FILENAMESIZE - 1] = '\0';
1396  if (infilename[0] == '\0') {
1397  printf("Error: No filename.\n");
1398  return false;
1399  }
1400  if (strcmp(&infilename[strlen(infilename) - 4], ".ply") != 0) {
1401  strcat(infilename, ".ply");
1402  }
1403 
1404  if (!(fp = fopen(infilename, "r"))) {
1405  printf("Error: Unable to open file %s\n", infilename);
1406  return false;
1407  }
1408  printf("Opening %s.\n", infilename);
1409 
1410  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1411  if (!endheader) {
1412  // Find if it is the keyword "end_header".
1413  str = strstr(bufferp, "end_header");
1414  // strstr() is case sensitive.
1415  if (!str) str = strstr(bufferp, "End_header");
1416  if (!str) str = strstr(bufferp, "End_Header");
1417  if (str) {
1418  // This is the end of the header section.
1419  endheader = 1;
1420  continue;
1421  }
1422  // Parse the number of vertices and the number of faces.
1423  if (nverts == 0 || nfaces == 0) {
1424  // Find if it si the keyword "element".
1425  str = strstr(bufferp, "element");
1426  if (!str) str = strstr(bufferp, "Element");
1427  if (str) {
1428  bufferp = findnextfield(str);
1429  if (*bufferp == '\0') {
1430  printf("Syntax error reading element type on line%d in file %s\n",
1431  line_count, infilename);
1432  fclose(fp);
1433  return false;
1434  }
1435  if (nverts == 0) {
1436  // Find if it is the keyword "vertex".
1437  str = strstr(bufferp, "vertex");
1438  if (!str) str = strstr(bufferp, "Vertex");
1439  if (str) {
1440  bufferp = findnextnumber(str);
1441  if (*bufferp == '\0') {
1442  printf("Syntax error reading vertex number on line");
1443  printf(" %d in file %s\n", line_count, infilename);
1444  fclose(fp);
1445  return false;
1446  }
1447  nverts = (int) strtol(bufferp, &bufferp, 0);
1448  // Allocate memory for 'tetgenio'
1449  if (nverts > 0) {
1450  numberofpoints = nverts;
1451  pointlist = new REAL[nverts * 3];
1452  smallestidx = nverts + 1; // A big enough index.
1453  }
1454  }
1455  }
1456  if (nfaces == 0) {
1457  // Find if it is the keyword "face".
1458  str = strstr(bufferp, "face");
1459  if (!str) str = strstr(bufferp, "Face");
1460  if (str) {
1461  bufferp = findnextnumber(str);
1462  if (*bufferp == '\0') {
1463  printf("Syntax error reading face number on line");
1464  printf(" %d in file %s\n", line_count, infilename);
1465  fclose(fp);
1466  return false;
1467  }
1468  nfaces = (int) strtol(bufferp, &bufferp, 0);
1469  // Allocate memory for 'tetgenio'
1470  if (nfaces > 0) {
1471  numberoffacets = nfaces;
1472  facetlist = new tetgenio::facet[nfaces];
1473  }
1474  }
1475  }
1476  } // It is not the string "element".
1477  }
1478  if (format == 0) {
1479  // Find the keyword "format".
1480  str = strstr(bufferp, "format");
1481  if (!str) str = strstr(bufferp, "Format");
1482  if (str) {
1483  format = 1;
1484  bufferp = findnextfield(str);
1485  // Find if it is the string "ascii".
1486  str = strstr(bufferp, "ascii");
1487  if (!str) str = strstr(bufferp, "ASCII");
1488  if (!str) {
1489  printf("This routine only reads ascii format of ply files.\n");
1490  printf("Hint: You can convert the binary to ascii format by\n");
1491  printf(" using the provided ply tools:\n");
1492  printf(" ply2ascii < %s > ascii_%s\n", infilename, infilename);
1493  fclose(fp);
1494  return false;
1495  }
1496  }
1497  }
1498  } else if (iverts < nverts) {
1499  // Read vertex coordinates
1500  coord = &pointlist[iverts * 3];
1501  for (i = 0; i < 3; i++) {
1502  if (*bufferp == '\0') {
1503  printf("Syntax error reading vertex coords on line %d in file %s\n",
1504  line_count, infilename);
1505  fclose(fp);
1506  return false;
1507  }
1508  coord[i] = (REAL) strtod(bufferp, &bufferp);
1509  bufferp = findnextnumber(bufferp);
1510  }
1511  iverts++;
1512  } else if (ifaces < nfaces) {
1513  // Get next face
1514  f = &facetlist[ifaces];
1515  init(f);
1516  // In .off format, each facet has one polygon, no hole.
1517  f->numberofpolygons = 1;
1518  f->polygonlist = new tetgenio::polygon[1];
1519  p = &f->polygonlist[0];
1520  init(p);
1521  // Read the number of vertices, it should be greater than 0.
1522  p->numberofvertices = (int) strtol(bufferp, &bufferp, 0);
1523  if (p->numberofvertices == 0) {
1524  printf("Syntax error reading polygon on line %d in file %s\n",
1525  line_count, infilename);
1526  fclose(fp);
1527  return false;
1528  }
1529  // Allocate memory for face vertices
1530  p->vertexlist = new int[p->numberofvertices];
1531  for (i = 0; i < p->numberofvertices; i++) {
1532  bufferp = findnextnumber(bufferp);
1533  if (*bufferp == '\0') {
1534  printf("Syntax error reading polygon on line %d in file %s\n",
1535  line_count, infilename);
1536  fclose(fp);
1537  return false;
1538  }
1539  p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0);
1540  if (p->vertexlist[i] < smallestidx) {
1541  smallestidx = p->vertexlist[i];
1542  }
1543  }
1544  ifaces++;
1545  } else {
1546  // Should never get here
1547  printf("Found extra text starting at line %d in file %s\n", line_count,
1548  infilename);
1549  break;
1550  }
1551  }
1552 
1553  // Close file
1554  fclose(fp);
1555 
1556  // Decide the firstnumber of the index.
1557  if (smallestidx == 0) {
1558  firstnumber = 0;
1559  } else if (smallestidx == 1) {
1560  firstnumber = 1;
1561  } else {
1562  printf("A wrong smallest index (%d) was detected in file %s\n",
1563  smallestidx, infilename);
1564  return false;
1565  }
1566 
1567  if (iverts != nverts) {
1568  printf("Expected %d vertices, but read only %d vertices in file %s\n",
1569  nverts, iverts, infilename);
1570  return false;
1571  }
1572  if (ifaces != nfaces) {
1573  printf("Expected %d faces, but read only %d faces in file %s\n",
1574  nfaces, ifaces, infilename);
1575  return false;
1576  }
1577 
1578  return true;
1579 }
1580 
1582 // //
1583 // load_stl() Load a surface mesh from a .stl file. //
1584 // //
1585 // The .stl or stereolithography format is an ASCII or binary file used in //
1586 // manufacturing. It is a list of the triangular surfaces that describe a //
1587 // computer generated solid model. This is the standard input for most rapid //
1588 // prototyping machines. //
1589 // //
1590 // Comment: A .stl file many contain many duplicated points. They will be //
1591 // unified during the Delaunay tetrahedralization process. //
1592 // //
1594 
1595 void SwapBytes(char *array, int size, int n)
1596 {
1597  char *x = new char[size];
1598  for(int i = 0; i < n; i++) {
1599  char *a = &array[i * size];
1600  memcpy(x, a, size);
1601  for(int c = 0; c < size; c++)
1602  a[size - 1 - c] = x[c];
1603  }
1604  delete [] x;
1605 }
1606 
1607 bool tetgenio::load_stl(const char* filebasename)
1608 {
1609  FILE *fp;
1610  tetgenmesh::arraypool *plist;
1611  tetgenio::facet *f;
1612  tetgenio::polygon *p;
1613  char infilename[FILENAMESIZE];
1614  char buffer[INPUTLINESIZE];
1615  char *bufferp, *str;
1616  double *coord;
1617  int solid = 0;
1618  int nverts = 0, iverts = 0;
1619  int nfaces = 0;
1620  int line_count = 0, i;
1621 
1622  strncpy(infilename, filebasename, FILENAMESIZE - 1);
1623  infilename[FILENAMESIZE - 1] = '\0';
1624  if (infilename[0] == '\0') {
1625  printf("Error: No filename.\n");
1626  return false;
1627  }
1628  if (strcmp(&infilename[strlen(infilename) - 4], ".stl") != 0) {
1629  strcat(infilename, ".stl");
1630  }
1631 
1632  if (!(fp = fopen(infilename, "rb"))) {
1633  printf("Error: Unable to open file %s\n", infilename);
1634  return false;
1635  }
1636  printf("Opening %s.\n", infilename);
1637 
1638  // "solid", or binary data header
1639  if(!fgets(buffer, sizeof(buffer), fp)){ fclose(fp); return 0; }
1640  bool binary = strncmp(buffer, "solid", 5) && strncmp(buffer, "SOLID", 5);
1641 
1642  // STL file has no number of points available. Use a list to read points.
1643  plist = new tetgenmesh::arraypool(sizeof(double) * 3, 10);
1644 
1645  if(!binary){
1646  solid = 1;
1647  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1648  // The ASCII .stl file must start with the lower case keyword solid and
1649  // end with endsolid.
1650  if (solid == 0) {
1651  // Read header
1652  bufferp = strstr(bufferp, "solid");
1653  if (bufferp != NULL) {
1654  solid = 1;
1655  }
1656  } else {
1657  // We're inside the block of the solid.
1658  str = bufferp;
1659  // Is this the end of the solid.
1660  bufferp = strstr(bufferp, "endsolid");
1661  if (bufferp != NULL) {
1662  solid = 0;
1663  } else {
1664  // Read the XYZ coordinates if it is a vertex.
1665  bufferp = str;
1666  bufferp = strstr(bufferp, "vertex");
1667  if (bufferp != NULL) {
1668  plist->newindex((void **) &coord);
1669  for (i = 0; i < 3; i++) {
1670  bufferp = findnextnumber(bufferp);
1671  if (*bufferp == '\0') {
1672  printf("Syntax error reading vertex coords on line %d\n",
1673  line_count);
1674  delete plist;
1675  fclose(fp);
1676  return false;
1677  }
1678  coord[i] = (REAL) strtod(bufferp, &bufferp);
1679  }
1680  }
1681  }
1682  }
1683  }
1684  } // if(!binary)
1685 
1686  else {
1687  rewind(fp);
1688  while(!feof(fp)) {
1689  char header[80];
1690  if(!fread(header, sizeof(char), 80, fp)) break;
1691  unsigned int nfacets = 0;
1692  size_t ret = fread(&nfacets, sizeof(unsigned int), 1, fp);
1693  bool swap = false;
1694  if(nfacets > 100000000){
1695  //Msg::Info("Swapping bytes from binary file");
1696  swap = true;
1697  SwapBytes((char*)&nfacets, sizeof(unsigned int), 1);
1698  }
1699  if(ret && nfacets){
1700  //points.resize(points.size() + 1);
1701  char *data = new char[nfacets * 50 * sizeof(char)];
1702  ret = fread(data, sizeof(char), nfacets * 50, fp);
1703  if(ret == nfacets * 50){
1704  for(unsigned int i = 0; i < nfacets; i++) {
1705  float *xyz = (float *)&data[i * 50 * sizeof(char)];
1706  if(swap) SwapBytes((char*)xyz, sizeof(float), 12);
1707  for(int j = 0; j < 3; j++){
1708  //SPoint3 p(xyz[3 + 3 * j], xyz[3 + 3 * j + 1], xyz[3 + 3 * j + 2]);
1709  //points.back().push_back(p);
1710  //bbox += p;
1711  plist->newindex((void **) &coord);
1712  coord[0] = xyz[3 + 3 * j];
1713  coord[1] = xyz[3 + 3 * j + 1];
1714  coord[2] = xyz[3 + 3 * j + 2];
1715  }
1716  }
1717  }
1718  delete [] data;
1719  }
1720  } // while (!feof(fp))
1721  } // binary
1722 
1723  fclose(fp);
1724 
1725  nverts = (int) plist->objects;
1726  // nverts should be an integer times 3 (every 3 vertices denote a face).
1727  if (nverts == 0 || (nverts % 3 != 0)) {
1728  printf("Error: Wrong number of vertices in file %s.\n", infilename);
1729  delete plist;
1730  return false;
1731  }
1732  numberofpoints = nverts;
1733  pointlist = new REAL[nverts * 3];
1734  for (i = 0; i < nverts; i++) {
1735  coord = (double *) fastlookup(plist, i);
1736  iverts = i * 3;
1737  pointlist[iverts] = (REAL) coord[0];
1738  pointlist[iverts + 1] = (REAL) coord[1];
1739  pointlist[iverts + 2] = (REAL) coord[2];
1740  }
1741 
1742  nfaces = (int) (nverts / 3);
1743  numberoffacets = nfaces;
1744  facetlist = new tetgenio::facet[nfaces];
1745 
1746  // Default use '1' as the array starting index.
1747  firstnumber = 1;
1748  iverts = firstnumber;
1749  for (i = 0; i < nfaces; i++) {
1750  f = &facetlist[i];
1751  init(f);
1752  // In .stl format, each facet has one polygon, no hole.
1753  f->numberofpolygons = 1;
1754  f->polygonlist = new tetgenio::polygon[1];
1755  p = &f->polygonlist[0];
1756  init(p);
1757  // Each polygon has three vertices.
1758  p->numberofvertices = 3;
1759  p->vertexlist = new int[p->numberofvertices];
1760  p->vertexlist[0] = iverts;
1761  p->vertexlist[1] = iverts + 1;
1762  p->vertexlist[2] = iverts + 2;
1763  iverts += 3;
1764  }
1765 
1766  delete plist;
1767  return true;
1768 }
1769 
1771 // //
1772 // load_medit() Load a surface mesh from a .mesh file. //
1773 // //
1774 // The .mesh format is the file format of Medit, a user-friendly interactive //
1775 // mesh viewer program. //
1776 // //
1778 
1779 bool tetgenio::load_medit(const char* filebasename, int istetmesh)
1780 {
1781  FILE *fp;
1782  tetgenio::facet *tmpflist, *f;
1783  tetgenio::polygon *p;
1784  char infilename[FILENAMESIZE];
1785  char buffer[INPUTLINESIZE];
1786  char *bufferp, *str;
1787  double *coord;
1788  int *tmpfmlist;
1789  int dimension = 0;
1790  int nverts = 0;
1791  int nfaces = 0;
1792  int ntets = 0;
1793  int line_count = 0;
1794  int corners = 0; // 3 (triangle) or 4 (quad).
1795  int *plist;
1796  int i, j;
1797 
1798  int smallestidx = 0;
1799 
1800  strncpy(infilename, filebasename, FILENAMESIZE - 1);
1801  infilename[FILENAMESIZE - 1] = '\0';
1802  if (infilename[0] == '\0') {
1803  printf("Error: No filename.\n");
1804  return false;
1805  }
1806  if (strcmp(&infilename[strlen(infilename) - 5], ".mesh") != 0) {
1807  strcat(infilename, ".mesh");
1808  }
1809 
1810  if (!(fp = fopen(infilename, "r"))) {
1811  printf("Error: Unable to open file %s\n", infilename);
1812  return false;
1813  }
1814  printf("Opening %s.\n", infilename);
1815 
1816  while ((bufferp = readline(buffer, fp, &line_count)) != NULL) {
1817  if (*bufferp == '#') continue; // A comment line is skipped.
1818  if (dimension == 0) {
1819  // Find if it is the keyword "Dimension".
1820  str = strstr(bufferp, "Dimension");
1821  if (!str) str = strstr(bufferp, "dimension");
1822  if (!str) str = strstr(bufferp, "DIMENSION");
1823  if (str) {
1824  // Read the dimensions
1825  bufferp = findnextnumber(str); // Skip field "Dimension".
1826  if (*bufferp == '\0') {
1827  // Read a non-empty line.
1828  bufferp = readline(buffer, fp, &line_count);
1829  }
1830  dimension = (int) strtol(bufferp, &bufferp, 0);
1831  if (dimension != 2 && dimension != 3) {
1832  printf("Unknown dimension in file on line %d in file %s\n",
1833  line_count, infilename);
1834  fclose(fp);
1835  return false;
1836  }
1837  mesh_dim = dimension;
1838  }
1839  }
1840  if (nverts == 0) {
1841  // Find if it is the keyword "Vertices".
1842  str = strstr(bufferp, "Vertices");
1843  if (!str) str = strstr(bufferp, "vertices");
1844  if (!str) str = strstr(bufferp, "VERTICES");
1845  if (str) {
1846  // Read the number of vertices.
1847  bufferp = findnextnumber(str); // Skip field "Vertices".
1848  if (*bufferp == '\0') {
1849  // Read a non-empty line.
1850  bufferp = readline(buffer, fp, &line_count);
1851  }
1852  nverts = (int) strtol(bufferp, &bufferp, 0);
1853  // Initialize the smallest index.
1854  smallestidx = nverts + 1;
1855  // Allocate memory for 'tetgenio'
1856  if (nverts > 0) {
1857  numberofpoints = nverts;
1858  pointlist = new REAL[nverts * 3];
1859  }
1860  // Read the follwoing node list.
1861  for (i = 0; i < nverts; i++) {
1862  bufferp = readline(buffer, fp, &line_count);
1863  if (bufferp == NULL) {
1864  printf("Unexpected end of file on line %d in file %s\n",
1865  line_count, infilename);
1866  fclose(fp);
1867  return false;
1868  }
1869  // Read vertex coordinates
1870  coord = &pointlist[i * 3];
1871  for (j = 0; j < 3; j++) {
1872  if (*bufferp == '\0') {
1873  printf("Syntax error reading vertex coords on line");
1874  printf(" %d in file %s\n", line_count, infilename);
1875  fclose(fp);
1876  return false;
1877  }
1878  if ((j < 2) || (dimension == 3)) {
1879  coord[j] = (REAL) strtod(bufferp, &bufferp);
1880  } else {
1881  coord[j] = 0.0;
1882  }
1883  bufferp = findnextnumber(bufferp);
1884  }
1885  }
1886  continue;
1887  }
1888  }
1889  if (ntets == 0) {
1890  // Find if it is the keyword "Tetrahedra"
1891  corners = 0;
1892  str = strstr(bufferp, "Tetrahedra");
1893  if (!str) str = strstr(bufferp, "tetrahedra");
1894  if (!str) str = strstr(bufferp, "TETRAHEDRA");
1895  if (str) {
1896  corners = 4;
1897  }
1898  if (corners == 4) {
1899  // Read the number of tetrahedra
1900  bufferp = findnextnumber(str); // Skip field "Tetrahedra".
1901  if (*bufferp == '\0') {
1902  // Read a non-empty line.
1903  bufferp = readline(buffer, fp, &line_count);
1904  }
1905  ntets = strtol(bufferp, &bufferp, 0);
1906  if (ntets > 0) {
1907  // It is a tetrahedral mesh.
1908  numberoftetrahedra = ntets;
1909  numberofcorners = 4;
1910  numberoftetrahedronattributes = 1;
1911  tetrahedronlist = new int[ntets * 4];
1912  tetrahedronattributelist = new REAL[ntets];
1913  }
1914  } // if (corners == 4)
1915  // Read the list of tetrahedra.
1916  for (i = 0; i < numberoftetrahedra; i++) {
1917  plist = &(tetrahedronlist[i * 4]);
1918  bufferp = readline(buffer, fp, &line_count);
1919  if (bufferp == NULL) {
1920  printf("Unexpected end of file on line %d in file %s\n",
1921  line_count, infilename);
1922  fclose(fp);
1923  return false;
1924  }
1925  // Read the vertices of the tet.
1926  for (j = 0; j < corners; j++) {
1927  if (*bufferp == '\0') {
1928  printf("Syntax error reading face on line %d in file %s\n",
1929  line_count, infilename);
1930  fclose(fp);
1931  return false;
1932  }
1933  plist[j] = (int) strtol(bufferp, &bufferp, 0);
1934  // Remember the smallest index.
1935  if (plist[j] < smallestidx) smallestidx = plist[j];
1936  bufferp = findnextnumber(bufferp);
1937  }
1938  // Read the attribute of the tet if it exists.
1939  tetrahedronattributelist[i] = 0;
1940  if (*bufferp != '\0') {
1941  tetrahedronattributelist[i] = (REAL) strtol(bufferp, &bufferp, 0);
1942  }
1943  } // i
1944  } // Tetrahedra
1945  if (nfaces == 0) {
1946  // Find if it is the keyword "Triangles" or "Quadrilaterals".
1947  corners = 0;
1948  str = strstr(bufferp, "Triangles");
1949  if (!str) str = strstr(bufferp, "triangles");
1950  if (!str) str = strstr(bufferp, "TRIANGLES");
1951  if (str) {
1952  corners = 3;
1953  } else {
1954  str = strstr(bufferp, "Quadrilaterals");
1955  if (!str) str = strstr(bufferp, "quadrilaterals");
1956  if (!str) str = strstr(bufferp, "QUADRILATERALS");
1957  if (str) {
1958  corners = 4;
1959  }
1960  }
1961  if (corners == 3 || corners == 4) {
1962  // Read the number of triangles (or quadrilaterals).
1963  bufferp = findnextnumber(str); // Skip field "Triangles".
1964  if (*bufferp == '\0') {
1965  // Read a non-empty line.
1966  bufferp = readline(buffer, fp, &line_count);
1967  }
1968  nfaces = strtol(bufferp, &bufferp, 0);
1969  // Allocate memory for 'tetgenio'
1970  if (nfaces > 0) {
1971  if (!istetmesh) {
1972  // It is a PLC surface mesh.
1973  if (numberoffacets > 0) {
1974  // facetlist has already been allocated. Enlarge arrays.
1975  // This happens when the surface mesh contains mixed cells.
1976  tmpflist = new tetgenio::facet[numberoffacets + nfaces];
1977  tmpfmlist = new int[numberoffacets + nfaces];
1978  // Copy the data of old arrays into new arrays.
1979  for (i = 0; i < numberoffacets; i++) {
1980  f = &(tmpflist[i]);
1981  tetgenio::init(f);
1982  *f = facetlist[i];
1983  tmpfmlist[i] = facetmarkerlist[i];
1984  }
1985  // Release old arrays.
1986  delete [] facetlist;
1987  delete [] facetmarkerlist;
1988  // Remember the new arrays.
1989  facetlist = tmpflist;
1990  facetmarkerlist = tmpfmlist;
1991  } else {
1992  // This is the first time to allocate facetlist.
1993  facetlist = new tetgenio::facet[nfaces];
1994  facetmarkerlist = new int[nfaces];
1995  }
1996  } else {
1997  if (corners == 3) {
1998  // It is a surface mesh of a tetrahedral mesh.
1999  numberoftrifaces = nfaces;
2000  trifacelist = new int[nfaces * 3];
2001  trifacemarkerlist = new int[nfaces];
2002  }
2003  }
2004  } // if (nfaces > 0)
2005  // Read the following list of faces.
2006  if (!istetmesh) {
2007  for (i = numberoffacets; i < numberoffacets + nfaces; i++) {
2008  bufferp = readline(buffer, fp, &line_count);
2009  if (bufferp == NULL) {
2010  printf("Unexpected end of file on line %d in file %s\n",
2011  line_count, infilename);
2012  fclose(fp);
2013  return false;
2014  }
2015  f = &facetlist[i];
2016  tetgenio::init(f);
2017  // In .mesh format, each facet has one polygon, no hole.
2018  f->numberofpolygons = 1;
2019  f->polygonlist = new tetgenio::polygon[1];
2020  p = &f->polygonlist[0];
2021  tetgenio::init(p);
2022  p->numberofvertices = corners;
2023  // Allocate memory for face vertices
2024  p->vertexlist = new int[p->numberofvertices];
2025  // Read the vertices of the face.
2026  for (j = 0; j < corners; j++) {
2027  if (*bufferp == '\0') {
2028  printf("Syntax error reading face on line %d in file %s\n",
2029  line_count, infilename);
2030  fclose(fp);
2031  return false;
2032  }
2033  p->vertexlist[j] = (int) strtol(bufferp, &bufferp, 0);
2034  // Remember the smallest index.
2035  if (p->vertexlist[j] < smallestidx) {
2036  smallestidx = p->vertexlist[j];
2037  }
2038  bufferp = findnextnumber(bufferp);
2039  }
2040  // Read the marker of the face if it exists.
2041  facetmarkerlist[i] = 0;
2042  if (*bufferp != '\0') {
2043  facetmarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
2044  }
2045  }
2046  // Have read in a list of triangles/quads.
2047  numberoffacets += nfaces;
2048  nfaces = 0;
2049  } else {
2050  // It is a surface mesh of a tetrahedral mesh.
2051  if (corners == 3) {
2052  for (i = 0; i < numberoftrifaces; i++) {
2053  plist = &(trifacelist[i * 3]);
2054  bufferp = readline(buffer, fp, &line_count);
2055  if (bufferp == NULL) {
2056  printf("Unexpected end of file on line %d in file %s\n",
2057  line_count, infilename);
2058  fclose(fp);
2059  return false;
2060  }
2061  // Read the vertices of the face.
2062  for (j = 0; j < corners; j++) {
2063  if (*bufferp == '\0') {
2064  printf("Syntax error reading face on line %d in file %s\n",
2065  line_count, infilename);
2066  fclose(fp);
2067  return false;
2068  }
2069  plist[j] = (int) strtol(bufferp, &bufferp, 0);
2070  // Remember the smallest index.
2071  if (plist[j] < smallestidx) {
2072  smallestidx = plist[j];
2073  }
2074  bufferp = findnextnumber(bufferp);
2075  }
2076  // Read the marker of the face if it exists.
2077  trifacemarkerlist[i] = 0;
2078  if (*bufferp != '\0') {
2079  trifacemarkerlist[i] = (int) strtol(bufferp, &bufferp, 0);
2080  }
2081  } // i
2082  } // if (corners == 3)
2083  } // if (b->refine)
2084  } // if (corners == 3 || corners == 4)
2085  }
2086  }
2087 
2088  // Close file
2089  fclose(fp);
2090 
2091  // Decide the firstnumber of the index.
2092  if (smallestidx == 0) {
2093  firstnumber = 0;
2094  } else if (smallestidx == 1) {
2095  firstnumber = 1;
2096  } else {
2097  printf("A wrong smallest index (%d) was detected in file %s\n",
2098  smallestidx, infilename);
2099  return false;
2100  }
2101 
2102  return true;
2103 }
2104 
2106 // //
2107 // load_vtk() Load VTK surface mesh from file (.vtk ascii or binary). //
2108 // //
2109 // This function is contributed by: Bryn Lloyd, Computer Vision Laboratory, //
2110 // ETH, Zuerich. May 7, 2007. //
2111 // //
2113 
2114 // Two inline functions used in read/write VTK files.
2115 
2116 void swapBytes(unsigned char* var, int size)
2117 {
2118  int i = 0;
2119  int j = size - 1;
2120  char c;
2121 
2122  while (i < j) {
2123  c = var[i]; var[i] = var[j]; var[j] = c;
2124  i++, j--;
2125  }
2126 }
2127 
2128 bool testIsBigEndian()
2129 {
2130  short word = 0x4321;
2131  if((*(char *)& word) != 0x21)
2132  return true;
2133  else
2134  return false;
2135 }
2136 
2137 bool tetgenio::load_vtk(const char* filebasename)
2138 {
2139  FILE *fp;
2140  tetgenio::facet *f;
2141  tetgenio::polygon *p;
2142  char infilename[FILENAMESIZE];
2143  char line[INPUTLINESIZE];
2144  char mode[128], id[256], fmt[64];
2145  char *bufferp;
2146  double *coord;
2147  float _x, _y, _z;
2148  int nverts = 0;
2149  int nfaces = 0;
2150  int line_count = 0;
2151  int dummy;
2152  int id1, id2, id3;
2153  int nn = -1;
2154  int nn_old = -1;
2155  int i, j;
2156  bool ImALittleEndian = !testIsBigEndian();
2157 
2158  int smallestidx = 0;
2159 
2160  strncpy(infilename, filebasename, FILENAMESIZE - 1);
2161  infilename[FILENAMESIZE - 1] = '\0';
2162  if (infilename[0] == '\0') {
2163  printf("Error: No filename.\n");
2164  return false;
2165  }
2166  if (strcmp(&infilename[strlen(infilename) - 4], ".vtk") != 0) {
2167  strcat(infilename, ".vtk");
2168  }
2169  if (!(fp = fopen(infilename, "r"))) {
2170  printf("Error: Unable to open file %s\n", infilename);
2171  return false;
2172  }
2173  printf("Opening %s.\n", infilename);
2174 
2175  // Default uses the index starts from '0'.
2176  firstnumber = 0;
2177  strcpy(mode, "BINARY");
2178 
2179  while((bufferp = readline(line, fp, &line_count)) != NULL) {
2180  if(strlen(line) == 0) continue;
2181  //swallow lines beginning with a comment sign or white space
2182  if(line[0] == '#' || line[0]=='\n' || line[0] == 10 || line[0] == 13 ||
2183  line[0] == 32) continue;
2184 
2185  sscanf(line, "%s", id);
2186  if(!strcmp(id, "ASCII")) {
2187  strcpy(mode, "ASCII");
2188  }
2189 
2190  if(!strcmp(id, "POINTS")) {
2191  sscanf(line, "%s %d %s", id, &nverts, fmt);
2192  if (nverts > 0) {
2193  numberofpoints = nverts;
2194  pointlist = new REAL[nverts * 3];
2195  smallestidx = nverts + 1;
2196  }
2197 
2198  if(!strcmp(mode, "BINARY")) {
2199  for(i = 0; i < nverts; i++) {
2200  coord = &pointlist[i * 3];
2201  if(!strcmp(fmt, "double")) {
2202  fread((char*)(&(coord[0])), sizeof(double), 1, fp);
2203  fread((char*)(&(coord[1])), sizeof(double), 1, fp);
2204  fread((char*)(&(coord[2])), sizeof(double), 1, fp);
2205  if(ImALittleEndian){
2206  swapBytes((unsigned char *) &(coord[0]), sizeof(coord[0]));
2207  swapBytes((unsigned char *) &(coord[1]), sizeof(coord[1]));
2208  swapBytes((unsigned char *) &(coord[2]), sizeof(coord[2]));
2209  }
2210  } else if(!strcmp(fmt, "float")) {
2211  fread((char*)(&_x), sizeof(float), 1, fp);
2212  fread((char*)(&_y), sizeof(float), 1, fp);
2213  fread((char*)(&_z), sizeof(float), 1, fp);
2214  if(ImALittleEndian){
2215  swapBytes((unsigned char *) &_x, sizeof(_x));
2216  swapBytes((unsigned char *) &_y, sizeof(_y));
2217  swapBytes((unsigned char *) &_z, sizeof(_z));
2218  }
2219  coord[0] = double(_x);
2220  coord[1] = double(_y);
2221  coord[2] = double(_z);
2222  } else {
2223  printf("Error: Only float or double formats are supported!\n");
2224  return false;
2225  }
2226  }
2227  } else if(!strcmp(mode, "ASCII")) {
2228  for(i = 0; i < nverts; i++){
2229  bufferp = readline(line, fp, &line_count);
2230  if (bufferp == NULL) {
2231  printf("Unexpected end of file on line %d in file %s\n",
2232  line_count, infilename);
2233  fclose(fp);
2234  return false;
2235  }
2236  // Read vertex coordinates
2237  coord = &pointlist[i * 3];
2238  for (j = 0; j < 3; j++) {
2239  if (*bufferp == '\0') {
2240  printf("Syntax error reading vertex coords on line");
2241  printf(" %d in file %s\n", line_count, infilename);
2242  fclose(fp);
2243  return false;
2244  }
2245  coord[j] = (REAL) strtod(bufferp, &bufferp);
2246  bufferp = findnextnumber(bufferp);
2247  }
2248  }
2249  }
2250  continue;
2251  }
2252 
2253  if(!strcmp(id, "POLYGONS")) {
2254  sscanf(line, "%s %d %d", id, &nfaces, &dummy);
2255  if (nfaces > 0) {
2256  numberoffacets = nfaces;
2257  facetlist = new tetgenio::facet[nfaces];
2258  }
2259 
2260  if(!strcmp(mode, "BINARY")) {
2261  for(i = 0; i < nfaces; i++){
2262  fread((char*)(&nn), sizeof(int), 1, fp);
2263  if(ImALittleEndian){
2264  swapBytes((unsigned char *) &nn, sizeof(nn));
2265  }
2266  if (i == 0)
2267  nn_old = nn;
2268  if (nn != nn_old) {
2269  printf("Error: No mixed cells are allowed.\n");
2270  return false;
2271  }
2272 
2273  if(nn == 3){
2274  fread((char*)(&id1), sizeof(int), 1, fp);
2275  fread((char*)(&id2), sizeof(int), 1, fp);
2276  fread((char*)(&id3), sizeof(int), 1, fp);
2277  if(ImALittleEndian){
2278  swapBytes((unsigned char *) &id1, sizeof(id1));
2279  swapBytes((unsigned char *) &id2, sizeof(id2));
2280  swapBytes((unsigned char *) &id3, sizeof(id3));
2281  }
2282  f = &facetlist[i];
2283  init(f);
2284  // In .off format, each facet has one polygon, no hole.
2285  f->numberofpolygons = 1;
2286  f->polygonlist = new tetgenio::polygon[1];
2287  p = &f->polygonlist[0];
2288  init(p);
2289  // Set number of vertices
2290  p->numberofvertices = 3;
2291  // Allocate memory for face vertices
2292  p->vertexlist = new int[p->numberofvertices];
2293  p->vertexlist[0] = id1;
2294  p->vertexlist[1] = id2;
2295  p->vertexlist[2] = id3;
2296  // Detect the smallest index.
2297  for (j = 0; j < 3; j++) {
2298  if (p->vertexlist[j] < smallestidx) {
2299  smallestidx = p->vertexlist[j];
2300  }
2301  }
2302  } else {
2303  printf("Error: Only triangles are supported\n");
2304  return false;
2305  }
2306  }
2307  } else if(!strcmp(mode, "ASCII")) {
2308  for(i = 0; i < nfaces; i++) {
2309  bufferp = readline(line, fp, &line_count);
2310  nn = (int) strtol(bufferp, &bufferp, 0);
2311  if (i == 0)
2312  nn_old = nn;
2313  if (nn != nn_old) {
2314  printf("Error: No mixed cells are allowed.\n");
2315  return false;
2316  }
2317 
2318  if (nn == 3) {
2319  bufferp = findnextnumber(bufferp); // Skip the first field.
2320  id1 = (int) strtol(bufferp, &bufferp, 0);
2321  bufferp = findnextnumber(bufferp);
2322  id2 = (int) strtol(bufferp, &bufferp, 0);
2323  bufferp = findnextnumber(bufferp);
2324  id3 = (int) strtol(bufferp, &bufferp, 0);
2325  f = &facetlist[i];
2326  init(f);
2327  // In .off format, each facet has one polygon, no hole.
2328  f->numberofpolygons = 1;
2329  f->polygonlist = new tetgenio::polygon[1];
2330  p = &f->polygonlist[0];
2331  init(p);
2332  // Set number of vertices
2333  p->numberofvertices = 3;
2334  // Allocate memory for face vertices
2335  p->vertexlist = new int[p->numberofvertices];
2336  p->vertexlist[0] = id1;
2337  p->vertexlist[1] = id2;
2338  p->vertexlist[2] = id3;
2339  // Detect the smallest index.
2340  for (j = 0; j < 3; j++) {
2341  if (p->vertexlist[j] < smallestidx) {
2342  smallestidx = p->vertexlist[j];
2343  }
2344  }
2345  } else {
2346  printf("Error: Only triangles are supported.\n");
2347  return false;
2348  }
2349  }
2350  }
2351 
2352  fclose(fp);
2353 
2354  // Decide the firstnumber of the index.
2355  if (smallestidx == 0) {
2356  firstnumber = 0;
2357  } else if (smallestidx == 1) {
2358  firstnumber = 1;
2359  } else {
2360  printf("A wrong smallest index (%d) was detected in file %s\n",
2361  smallestidx, infilename);
2362  return false;
2363  }
2364 
2365  return true;
2366  }
2367 
2368  if(!strcmp(id,"LINES") || !strcmp(id,"CELLS")){
2369  printf("Warning: load_vtk(): cannot read formats LINES, CELLS.\n");
2370  }
2371  } // while ()
2372 
2373  return true;
2374 }
2375 
2377 // //
2378 // load_plc() Load a piecewise linear complex from file(s). //
2379 // //
2381 
2382 bool tetgenio::load_plc(const char* filebasename, int object)
2383 {
2384  bool success;
2385 
2386  if (object == (int) tetgenbehavior::NODES) {
2387  success = load_node(filebasename);
2388  } else if (object == (int) tetgenbehavior::POLY) {
2389  success = load_poly(filebasename);
2390  } else if (object == (int) tetgenbehavior::OFF) {
2391  success = load_off(filebasename);
2392  } else if (object == (int) tetgenbehavior::PLY) {
2393  success = load_ply(filebasename);
2394  } else if (object == (int) tetgenbehavior::STL) {
2395  success = load_stl(filebasename);
2396  } else if (object == (int) tetgenbehavior::MEDIT) {
2397  success = load_medit(filebasename, 0);
2398  } else if (object == (int) tetgenbehavior::VTK) {
2399  success = load_vtk(filebasename);
2400  } else {
2401  success = load_poly(filebasename);
2402  }
2403 
2404  if (success) {
2405  // Try to load the following files (.edge, .var, .mtr).
2406  load_edge(filebasename);
2407  load_var(filebasename);
2408  load_mtr(filebasename);
2409  }
2410 
2411  return success;
2412 }
2413 
2415 // //
2416 // load_mesh() Load a tetrahedral mesh from file(s). //
2417 // //
2419 
2420 bool tetgenio::load_tetmesh(const char* filebasename, int object)
2421 {
2422  bool success;
2423 
2424  if (object == (int) tetgenbehavior::MEDIT) {
2425  success = load_medit(filebasename, 1);
2426  } else if (object == (int) tetgenbehavior::NEU_MESH) {
2427  //success = load_neumesh(filebasename, 1);
2428  success = false;
2429  } else {
2430  success = load_node(filebasename);
2431  if (success) {
2432  success = load_tet(filebasename);
2433  }
2434  if (success) {
2435  // Try to load the following files (.face, .edge, .vol).
2436  load_face(filebasename);
2437  load_edge(filebasename);
2438  load_vol(filebasename);
2439  }
2440  }
2441 
2442  //if (success) {
2443  // Try to load the following files (.var, .mtr).
2444  load_var(filebasename);
2445  load_mtr(filebasename);
2446  //}
2447 
2448  return success;
2449 }
2450 
2452 // //
2453 // save_nodes() Save points to a .node file. //
2454 // //
2456 
2457 void tetgenio::save_nodes(const char* filebasename)
2458 {
2459  FILE *fout;
2460  char outnodefilename[FILENAMESIZE];
2461  char outmtrfilename[FILENAMESIZE];
2462  int i, j;
2463 
2464  sprintf(outnodefilename, "%s.node", filebasename);
2465  std::cout << "Saving nodes to " << outnodefilename << std::endl;
2466  fout = fopen(outnodefilename, "w");
2467  fprintf(fout, "%d %d %d %d\n", numberofpoints, mesh_dim,
2468  numberofpointattributes, pointmarkerlist != NULL ? 1 : 0);
2469  for (i = 0; i < numberofpoints; i++) {
2470  if (mesh_dim == 2) {
2471  fprintf(fout, "%d %.16g %.16g", i + firstnumber, pointlist[i * 3],
2472  pointlist[i * 3 + 1]);
2473  } else {
2474  fprintf(fout, "%d %.16g %.16g %.16g", i + firstnumber,
2475  pointlist[i * 3], pointlist[i * 3 + 1], pointlist[i * 3 + 2]);
2476  }
2477  for (j = 0; j < numberofpointattributes; j++) {
2478  fprintf(fout, " %.16g",
2479  pointattributelist[i * numberofpointattributes + j]);
2480  }
2481  if (pointmarkerlist != NULL) {
2482  fprintf(fout, " %d", pointmarkerlist[i]);
2483  }
2484  fprintf(fout, "\n");
2485  }
2486  fclose(fout);
2487 
2488  // If the point metrics exist, output them to a .mtr file.
2489  if ((numberofpointmtrs > 0) && (pointmtrlist != (REAL *) NULL)) {
2490  sprintf(outmtrfilename, "%s.mtr", filebasename);
2491  std::cout << "Saving metrics to " << outmtrfilename << std::endl;
2492  fout = fopen(outmtrfilename, "w");
2493  fprintf(fout, "%d %d\n", numberofpoints, numberofpointmtrs);
2494  for (i = 0; i < numberofpoints; i++) {
2495  for (j = 0; j < numberofpointmtrs; j++) {
2496  fprintf(fout, "%.16g ", pointmtrlist[i * numberofpointmtrs + j]);
2497  }
2498  fprintf(fout, "\n");
2499  }
2500  fclose(fout);
2501  }
2502 }
2503 
2505 // //
2506 // save_elements() Save elements to a .ele file. //
2507 // //
2509 
2510 void tetgenio::save_elements(const char* filebasename)
2511 {
2512  FILE *fout;
2513  char outelefilename[FILENAMESIZE];
2514  int i, j;
2515 
2516  sprintf(outelefilename, "%s.ele", filebasename);
2517  std::cout << "Saving elements to " << outelefilename << std::endl;
2518  fout = fopen(outelefilename, "w");
2519  if (mesh_dim == 3) {
2520  fprintf(fout, "%d %d %d\n", numberoftetrahedra, numberofcorners,
2521  numberoftetrahedronattributes);
2522  for (i = 0; i < numberoftetrahedra; i++) {
2523  fprintf(fout, "%d", i + firstnumber);
2524  for (j = 0; j < numberofcorners; j++) {
2525  fprintf(fout, " %5d", tetrahedronlist[i * numberofcorners + j]);
2526  }
2527  for (j = 0; j < numberoftetrahedronattributes; j++) {
2528  fprintf(fout, " %g",
2529  tetrahedronattributelist[i * numberoftetrahedronattributes + j]);
2530  }
2531  fprintf(fout, "\n");
2532  }
2533  } else {
2534  // Save a two-dimensional mesh.
2535  fprintf(fout, "%d %d %d\n",numberoftrifaces,3,trifacemarkerlist ? 1 : 0);
2536  for (i = 0; i < numberoftrifaces; i++) {
2537  fprintf(fout, "%d", i + firstnumber);
2538  for (j = 0; j < 3; j++) {
2539  fprintf(fout, " %5d", trifacelist[i * 3 + j]);
2540  }
2541  if (trifacemarkerlist != NULL) {
2542  fprintf(fout, " %d", trifacemarkerlist[i]);
2543  }
2544  fprintf(fout, "\n");
2545  }
2546  }
2547 
2548  fclose(fout);
2549 }
2550 
2552 // //
2553 // save_faces() Save faces to a .face file. //
2554 // //
2556 
2557 void tetgenio::save_faces(const char* filebasename)
2558 {
2559  FILE *fout;
2560  char outfacefilename[FILENAMESIZE];
2561  int i;
2562 
2563  sprintf(outfacefilename, "%s.face", filebasename);
2564  std::cout << "Saving faces to " << outfacefilename << std::endl;
2565  fout = fopen(outfacefilename, "w");
2566  fprintf(fout, "%d %d\n", numberoftrifaces,
2567  trifacemarkerlist != NULL ? 1 : 0);
2568  for (i = 0; i < numberoftrifaces; i++) {
2569  fprintf(fout, "%d %5d %5d %5d", i + firstnumber, trifacelist[i * 3],
2570  trifacelist[i * 3 + 1], trifacelist[i * 3 + 2]);
2571  if (trifacemarkerlist != NULL) {
2572  fprintf(fout, " %d", trifacemarkerlist[i]);
2573  }
2574  fprintf(fout, "\n");
2575  }
2576 
2577  fclose(fout);
2578 }
2579 
2581 // //
2582 // save_edges() Save egdes to a .edge file. //
2583 // //
2585 
2586 void tetgenio::save_edges(const char* filebasename)
2587 {
2588  FILE *fout;
2589  char outedgefilename[FILENAMESIZE];
2590  int i;
2591 
2592  sprintf(outedgefilename, "%s.edge", filebasename);
2593  std::cout << "Saving edges to " << outedgefilename << std::endl;
2594  fout = fopen(outedgefilename, "w");
2595  fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
2596  for (i = 0; i < numberofedges; i++) {
2597  fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2],
2598  edgelist[i * 2 + 1]);
2599  if (edgemarkerlist != NULL) {
2600  fprintf(fout, " %d", edgemarkerlist[i]);
2601  }
2602  fprintf(fout, "\n");
2603  }
2604 
2605  fclose(fout);
2606 }
2607 
2609 // //
2610 // save_neighbors() Save egdes to a .neigh file. //
2611 // //
2613 
2614 void tetgenio::save_neighbors(const char* filebasename)
2615 {
2616  FILE *fout;
2617  char outneighborfilename[FILENAMESIZE];
2618  int i;
2619 
2620  sprintf(outneighborfilename, "%s.neigh", filebasename);
2621  std::cout << "Saving neighbors to " << outneighborfilename << std::endl;
2622  fout = fopen(outneighborfilename, "w");
2623  fprintf(fout, "%d %d\n", numberoftetrahedra, mesh_dim + 1);
2624  for (i = 0; i < numberoftetrahedra; i++) {
2625  if (mesh_dim == 2) {
2626  fprintf(fout, "%d %5d %5d %5d", i + firstnumber, neighborlist[i * 3],
2627  neighborlist[i * 3 + 1], neighborlist[i * 3 + 2]);
2628  } else {
2629  fprintf(fout, "%d %5d %5d %5d %5d", i + firstnumber,
2630  neighborlist[i * 4], neighborlist[i * 4 + 1],
2631  neighborlist[i * 4 + 2], neighborlist[i * 4 + 3]);
2632  }
2633  fprintf(fout, "\n");
2634  }
2635 
2636  fclose(fout);
2637 }
2638 
2640 // //
2641 // save_poly() Save segments or facets to a .poly file. //
2642 // //
2643 // It only save the facets, holes and regions. No .node file is saved. //
2644 // //
2646 
2647 void tetgenio::save_poly(const char* filebasename)
2648 {
2649  FILE *fout;
2650  facet *f;
2651  polygon *p;
2652  char outpolyfilename[FILENAMESIZE];
2653  int i, j, k;
2654 
2655  sprintf(outpolyfilename, "%s.poly", filebasename);
2656  std::cout << "Saving poly to " << outpolyfilename << std::endl;
2657  fout = fopen(outpolyfilename, "w");
2658 
2659  // The zero indicates that the vertices are in a separate .node file.
2660  // Followed by number of dimensions, number of vertex attributes,
2661  // and number of boundary markers (zero or one).
2662  fprintf(fout, "%d %d %d %d\n", 0, mesh_dim, numberofpointattributes,
2663  pointmarkerlist != NULL ? 1 : 0);
2664 
2665  // Save segments or facets.
2666  if (mesh_dim == 2) {
2667  // Number of segments, number of boundary markers (zero or one).
2668  fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0);
2669  for (i = 0; i < numberofedges; i++) {
2670  fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2],
2671  edgelist[i * 2 + 1]);
2672  if (edgemarkerlist != NULL) {
2673  fprintf(fout, " %d", edgemarkerlist[i]);
2674  }
2675  fprintf(fout, "\n");
2676  }
2677  } else {
2678  // Number of facets, number of boundary markers (zero or one).
2679  fprintf(fout, "%d %d\n", numberoffacets, facetmarkerlist != NULL ? 1 : 0);
2680  for (i = 0; i < numberoffacets; i++) {
2681  f = &(facetlist[i]);
2682  fprintf(fout, "%d %d %d # %d\n", f->numberofpolygons,f->numberofholes,
2683  facetmarkerlist != NULL ? facetmarkerlist[i] : 0, i + firstnumber);
2684  // Output polygons of this facet.
2685  for (j = 0; j < f->numberofpolygons; j++) {
2686  p = &(f->polygonlist[j]);
2687  fprintf(fout, "%d ", p->numberofvertices);
2688  for (k = 0; k < p->numberofvertices; k++) {
2689  if (((k + 1) % 10) == 0) {
2690  fprintf(fout, "\n ");
2691  }
2692  fprintf(fout, " %d", p->vertexlist[k]);
2693  }
2694  fprintf(fout, "\n");
2695  }
2696  // Output holes of this facet.
2697  for (j = 0; j < f->numberofholes; j++) {
2698  fprintf(fout, "%d %.12g %.12g %.12g\n", j + firstnumber,
2699  f->holelist[j * 3], f->holelist[j * 3 + 1], f->holelist[j * 3 + 2]);
2700  }
2701  }
2702  }
2703 
2704  // Save holes.
2705  fprintf(fout, "%d\n", numberofholes);
2706  for (i = 0; i < numberofholes; i++) {
2707  // Output x, y coordinates.
2708  fprintf(fout, "%d %.12g %.12g", i + firstnumber, holelist[i * mesh_dim],
2709  holelist[i * mesh_dim + 1]);
2710  if (mesh_dim == 3) {
2711  // Output z coordinate.
2712  fprintf(fout, " %.12g", holelist[i * mesh_dim + 2]);
2713  }
2714  fprintf(fout, "\n");
2715  }
2716 
2717  // Save regions.
2718  fprintf(fout, "%d\n", numberofregions);
2719  for (i = 0; i < numberofregions; i++) {
2720  if (mesh_dim == 2) {
2721  // Output the index, x, y coordinates, attribute (region number)
2722  // and maximum area constraint (maybe -1).
2723  fprintf(fout, "%d %.12g %.12g %.12g %.12g\n", i + firstnumber,
2724  regionlist[i * 4], regionlist[i * 4 + 1],
2725  regionlist[i * 4 + 2], regionlist[i * 4 + 3]);
2726  } else {
2727  // Output the index, x, y, z coordinates, attribute (region number)
2728  // and maximum volume constraint (maybe -1).
2729  fprintf(fout, "%d %.12g %.12g %.12g %.12g %.12g\n", i + firstnumber,
2730  regionlist[i * 5], regionlist[i * 5 + 1],
2731  regionlist[i * 5 + 2], regionlist[i * 5 + 3],
2732  regionlist[i * 5 + 4]);
2733  }
2734  }
2735 
2736  fclose(fout);
2737 }
2738 
2740 // //
2741 // save_faces2smesh() Save triangular faces to a .smesh file. //
2742 // //
2743 // It only save the facets. No holes and regions. No .node file. //
2744 // //
2746 
2747 void tetgenio::save_faces2smesh(char* filebasename)
2748 {
2749  FILE *fout;
2750  char outsmeshfilename[FILENAMESIZE];
2751  int i, j;
2752 
2753  sprintf(outsmeshfilename, "%s.smesh", filebasename);
2754  std::cout << "Saving faces to " << outsmeshfilename << std::endl;
2755  fout = fopen(outsmeshfilename, "w");
2756 
2757  // The zero indicates that the vertices are in a separate .node file.
2758  // Followed by number of dimensions, number of vertex attributes,
2759  // and number of boundary markers (zero or one).
2760  fprintf(fout, "%d %d %d %d\n", 0, mesh_dim, numberofpointattributes,
2761  pointmarkerlist != NULL ? 1 : 0);
2762 
2763  // Number of facets, number of boundary markers (zero or one).
2764  fprintf(fout, "%d %d\n", numberoftrifaces,
2765  trifacemarkerlist != NULL ? 1 : 0);
2766 
2767  // Output triangular facets.
2768  for (i = 0; i < numberoftrifaces; i++) {
2769  j = i * 3;
2770  fprintf(fout, "3 %d %d %d", trifacelist[j], trifacelist[j + 1],
2771  trifacelist[j + 2]);
2772  if (trifacemarkerlist != NULL) {
2773  fprintf(fout, " %d", trifacemarkerlist[i]);
2774  }
2775  fprintf(fout, "\n");
2776  }
2777 
2778  // No holes and regions.
2779  fprintf(fout, "0\n");
2780  fprintf(fout, "0\n");
2781 
2782  fclose(fout);
2783 }
2784 
2786 // //
2787 // readline() Read a nonempty line from a file. //
2788 // //
2789 // A line is considered "nonempty" if it contains something more than white //
2790 // spaces. If a line is considered empty, it will be dropped and the next //
2791 // line will be read, this process ends until reaching the end-of-file or a //
2792 // non-empty line. Return NULL if it is the end-of-file, otherwise, return //
2793 // a pointer to the first non-whitespace character of the line. //
2794 // //
2796 
2797 char* tetgenio::readline(char *string, FILE *infile, int *linenumber)
2798 {
2799  char *result;
2800 
2801  // Search for a non-empty line.
2802  do {
2803  result = fgets(string, INPUTLINESIZE - 1, infile);
2804  if (linenumber) (*linenumber)++;
2805  if (result == (char *) NULL) {
2806  return (char *) NULL;
2807  }
2808  // Skip white spaces.
2809  while ((*result == ' ') || (*result == '\t')) result++;
2810  // If it's end of line, read another line and try again.
2811  } while ((*result == '\0') || (*result == '\r') || (*result == '\n'));
2812  return result;
2813 }
2814 
2816 // //
2817 // findnextfield() Find the next field of a string. //
2818 // //
2819 // Jumps past the current field by searching for whitespace or a comma, then //
2820 // jumps past the whitespace or the comma to find the next field. //
2821 // //
2823 
2824 char* tetgenio::findnextfield(char *string)
2825 {
2826  char *result;
2827 
2828  result = string;
2829  // Skip the current field. Stop upon reaching whitespace or a comma.
2830  while ((*result != '\0') && (*result != ' ') && (*result != '\t') &&
2831  (*result != ',') && (*result != ';')) {
2832  result++;
2833  }
2834  // Now skip the whitespace or the comma, stop at anything else that looks
2835  // like a character, or the end of a line.
2836  while ((*result == ' ') || (*result == '\t') || (*result == ',') ||
2837  (*result == ';')) {
2838  result++;
2839  }
2840  return result;
2841 }
2842 
2844 // //
2845 // readnumberline() Read a nonempty number line from a file. //
2846 // //
2847 // A line is considered "nonempty" if it contains something that looks like //
2848 // a number. Comments (prefaced by `#') are ignored. //
2849 // //
2851 
2852 #pragma GCC diagnostic push
2853 #pragma GCC diagnostic ignored "-Wunused-parameter"
2854 char* tetgenio::readnumberline(char *string, FILE *infile, char *infilename)
2855 {
2856  char *result;
2857 
2858  // Search for something that looks like a number.
2859  do {
2860  result = fgets(string, INPUTLINESIZE, infile);
2861  if (result == (char *) NULL) {
2862  return result;
2863  }
2864  // Skip anything that doesn't look like a number, a comment,
2865  // or the end of a line.
2866  while ((*result != '\0') && (*result != '#')
2867  && (*result != '.') && (*result != '+') && (*result != '-')
2868  && ((*result < '0') || (*result > '9'))) {
2869  result++;
2870  }
2871  // If it's a comment or end of line, read another line and try again.
2872  } while ((*result == '#') || (*result == '\0'));
2873  return result;
2874 }
2875 #pragma GCC diagnostic pop
2876 // //
2878 // findnextnumber() Find the next field of a number string. //
2879 // //
2880 // Jumps past the current field by searching for whitespace or a comma, then //
2881 // jumps past the whitespace or the comma to find the next field that looks //
2882 // like a number. //
2883 // //
2885 
2886 char* tetgenio::findnextnumber(char *string)
2887 {
2888  char *result;
2889 
2890  result = string;
2891  // Skip the current field. Stop upon reaching whitespace or a comma.
2892  while ((*result != '\0') && (*result != '#') && (*result != ' ') &&
2893  (*result != '\t') && (*result != ',')) {
2894  result++;
2895  }
2896  // Now skip the whitespace and anything else that doesn't look like a
2897  // number, a comment, or the end of a line.
2898  while ((*result != '\0') && (*result != '#')
2899  && (*result != '.') && (*result != '+') && (*result != '-')
2900  && ((*result < '0') || (*result > '9'))) {
2901  result++;
2902  }
2903  // Check for a comment (prefixed with `#').
2904  if (*result == '#') {
2905  *result = '\0';
2906  }
2907  return result;
2908 }
2909 
2913 
2914 
2918 
2920 // //
2921 // syntax() Print list of command line switches. //
2922 // //
2924 
2925 void tetgenbehavior::syntax()
2926 {
2927  printf(" tetgen [-pYrq_Aa_miO_S_T_XMwcdzfenvgkJBNEFICQVh] input_file\n");
2928  printf(" -p Tetrahedralizes a piecewise linear complex (PLC).\n");
2929  printf(" -Y Preserves the input surface mesh (does not modify it).\n");
2930  printf(" -r Reconstructs a previously generated mesh.\n");
2931  printf(" -q Refines mesh (to improve mesh quality).\n");
2932  printf(" -R Mesh coarsening (to reduce the mesh elements).\n");
2933  printf(" -A Assigns attributes to tetrahedra in different regions.\n");
2934  printf(" -a Applies a maximum tetrahedron volume constraint.\n");
2935  printf(" -m Applies a mesh sizing function.\n");
2936  printf(" -i Inserts a list of additional points.\n");
2937  printf(" -O Specifies the level of mesh optimization.\n");
2938  printf(" -S Specifies maximum number of added points.\n");
2939  printf(" -T Sets a tolerance for coplanar test (default 1e-8).\n");
2940  printf(" -X Suppresses use of exact arithmetic.\n");
2941  printf(" -M No merge of coplanar facets or very close vertices.\n");
2942  printf(" -w Generates weighted Delaunay (regular) triangulation.\n");
2943  printf(" -c Retains the convex hull of the PLC.\n");
2944  printf(" -d Detects self-intersections of facets of the PLC.\n");
2945  printf(" -z Numbers all output items starting from zero.\n");
2946  printf(" -f Outputs all faces to .face file.\n");
2947  printf(" -e Outputs all edges to .edge file.\n");
2948  printf(" -n Outputs tetrahedra neighbors to .neigh file.\n");
2949  printf(" -v Outputs Voronoi diagram to files.\n");
2950  printf(" -g Outputs mesh to .mesh file for viewing by Medit.\n");
2951  printf(" -k Outputs mesh to .vtk file for viewing by Paraview.\n");
2952  printf(" -J No jettison of unused vertices from output .node file.\n");
2953  printf(" -B Suppresses output of boundary information.\n");
2954  printf(" -N Suppresses output of .node file.\n");
2955  printf(" -E Suppresses output of .ele file.\n");
2956  printf(" -F Suppresses output of .face and .edge file.\n");
2957  printf(" -I Suppresses mesh iteration numbers.\n");
2958  printf(" -C Checks the consistency of the final mesh.\n");
2959  printf(" -Q Quiet: No terminal output except errors.\n");
2960  printf(" -V Verbose: Detailed information, more terminal output.\n");
2961  printf(" -h Help: A brief instruction for using TetGen.\n");
2962 }
2963 
2965 // //
2966 // usage() Print a brief instruction for using TetGen. //
2967 // //
2969 
2970 void tetgenbehavior::usage()
2971 {
2972  printf("TetGen\n");
2973  printf("A Quality Tetrahedral Mesh Generator and 3D Delaunay ");
2974  printf("Triangulator\n");
2975  printf("Version 1.5\n");
2976  printf("August 18, 2018\n");
2977  printf("\n");
2978  printf("Copyright (C) 2002 - 2018\n");
2979  printf("\n");
2980  printf("What Can TetGen Do?\n");
2981  printf("\n");
2982  printf(" TetGen generates Delaunay tetrahedralizations, constrained\n");
2983  printf(" Delaunay tetrahedralizations, and quality tetrahedral meshes.\n");
2984  printf("\n");
2985  printf("Command Line Syntax:\n");
2986  printf("\n");
2987  printf(" Below is the basic command line syntax of TetGen with a list of ");
2988  printf("short\n");
2989  printf(" descriptions. Underscores indicate that numbers may optionally\n");
2990  printf(" follow certain switches. Do not leave any space between a ");
2991  printf("switch\n");
2992  printf(" and its numeric parameter. \'input_file\' contains input data\n");
2993  printf(" depending on the switches you supplied which may be a ");
2994  printf(" piecewise\n");
2995  printf(" linear complex or a list of nodes. File formats and detailed\n");
2996  printf(" description of command line switches are found in user's ");
2997  printf("manual.\n");
2998  printf("\n");
2999  syntax();
3000  printf("\n");
3001  printf("Examples of How to Use TetGen:\n");
3002  printf("\n");
3003  printf(" \'tetgen object\' reads vertices from object.node, and writes ");
3004  printf("their\n Delaunay tetrahedralization to object.1.node, ");
3005  printf("object.1.ele\n (tetrahedra), and object.1.face");
3006  printf(" (convex hull faces).\n");
3007  printf("\n");
3008  printf(" \'tetgen -p object\' reads a PLC from object.poly or object.");
3009  printf("smesh (and\n possibly object.node) and writes its constrained ");
3010  printf("Delaunay\n tetrahedralization to object.1.node, object.1.ele, ");
3011  printf("object.1.face,\n");
3012  printf(" (boundary faces) and object.1.edge (boundary edges).\n");
3013  printf("\n");
3014  printf(" \'tetgen -pq1.414a.1 object\' reads a PLC from object.poly or\n");
3015  printf(" object.smesh (and possibly object.node), generates a mesh ");
3016  printf("whose\n tetrahedra have radius-edge ratio smaller than 1.414 and ");
3017  printf("have volume\n of 0.1 or less, and writes the mesh to ");
3018  printf("object.1.node, object.1.ele,\n object.1.face, and object.1.edge\n");
3019  printf("\n");
3020  printf("Please send bugs/comments to Hang Si <si@wias-berlin.de>\n");
3021  terminatetetgen(NULL, 0);
3022 }
3023 
3025 // //
3026 // parse_commandline() Read the command line, identify switches, and set //
3027 // up options and file names. //
3028 // //
3029 // 'argc' and 'argv' are the same parameters passed to the function main() //
3030 // of a C/C++ program. They together represent the command line user invoked //
3031 // from an environment in which TetGen is running. //
3032 // //
3034 
3035 bool tetgenbehavior::parse_commandline(int argc, const char **argv)
3036 {
3037  int startindex;
3038  int increment;
3039  int meshnumber;
3040  int i, j, k;
3041  char workstring[1024];
3042 
3043  // First determine the input style of the switches.
3044  if (argc == 0) {
3045  startindex = 0; // Switches are given without a dash.
3046  argc = 1; // For running the following for-loop once.
3047  commandline[0] = '\0';
3048  } else {
3049  startindex = 1;
3050  strcpy(commandline, argv[0]);
3051  strcat(commandline, " ");
3052  }
3053 
3054  for (i = startindex; i < argc; i++) {
3055  // Remember the command line for output.
3056  strcat(commandline, argv[i]);
3057  strcat(commandline, " ");
3058  if (startindex == 1) {
3059  // Is this string a filename?
3060  if (argv[i][0] != '-') {
3061  strncpy(infilename, argv[i], 1024 - 1);
3062  infilename[1024 - 1] = '\0';
3063  continue;
3064  }
3065  }
3066  // Parse the individual switch from the string.
3067  for (j = startindex; argv[i][j] != '\0'; j++) {
3068  if (argv[i][j] == 'p') {
3069  plc = 1;
3070  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3071  (argv[i][j + 1] == '.')) {
3072  k = 0;
3073  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3074  (argv[i][j + 1] == '.')) {
3075  j++;
3076  workstring[k] = argv[i][j];
3077  k++;
3078  }
3079  workstring[k] = '\0';
3080  facet_separate_ang_tol = (REAL) strtod(workstring, (char **) NULL);
3081  }
3082  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3083  j++;
3084  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3085  (argv[i][j + 1] == '.')) {
3086  k = 0;
3087  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3088  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3089  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3090  j++;
3091  workstring[k] = argv[i][j];
3092  k++;
3093  }
3094  workstring[k] = '\0';
3095  facet_overlap_ang_tol = (REAL) strtod(workstring, (char **) NULL);
3096  }
3097  }
3098  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3099  j++;
3100  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3101  (argv[i][j + 1] == '.')) {
3102  k = 0;
3103  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3104  (argv[i][j + 1] == '.')) {
3105  j++;
3106  workstring[k] = argv[i][j];
3107  k++;
3108  }
3109  workstring[k] = '\0';
3110  facet_small_ang_tol = (REAL) strtod(workstring, (char **) NULL);
3111  }
3112  }
3113  } else if (argv[i][j] == 's') {
3114  psc = 1;
3115  } else if (argv[i][j] == 'Y') {
3116  nobisect = 1;
3117  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3118  nobisect_nomerge = (argv[i][j + 1] - '0');
3119  j++;
3120  }
3121  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3122  j++;
3123  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3124  supsteiner_level = (argv[i][j + 1] - '0');
3125  j++;
3126  }
3127  }
3128  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3129  j++;
3130  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3131  addsteiner_algo = (argv[i][j + 1] - '0');
3132  j++;
3133  }
3134  }
3135  } else if (argv[i][j] == 'r') {
3136  refine = 1;
3137  } else if (argv[i][j] == 'q') {
3138  quality = 1;
3139  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3140  (argv[i][j + 1] == '.')) {
3141  k = 0;
3142  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3143  (argv[i][j + 1] == '.')) {
3144  j++;
3145  workstring[k] = argv[i][j];
3146  k++;
3147  }
3148  workstring[k] = '\0';
3149  minratio = (REAL) strtod(workstring, (char **) NULL);
3150  }
3151  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3152  j++;
3153  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3154  (argv[i][j + 1] == '.')) {
3155  k = 0;
3156  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3157  (argv[i][j + 1] == '.')) {
3158  j++;
3159  workstring[k] = argv[i][j];
3160  k++;
3161  }
3162  workstring[k] = '\0';
3163  mindihedral = (REAL) strtod(workstring, (char **) NULL);
3164  }
3165  }
3166  } else if (argv[i][j] == 'R') {
3167  coarsen = 1;
3168  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3169  coarsen_param = (argv[i][j + 1] - '0');
3170  j++;
3171  }
3172  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3173  j++;
3174  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3175  (argv[i][j + 1] == '.')) {
3176  k = 0;
3177  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3178  (argv[i][j + 1] == '.')) {
3179  j++;
3180  workstring[k] = argv[i][j];
3181  k++;
3182  }
3183  workstring[k] = '\0';
3184  coarsen_percent = (REAL) strtod(workstring, (char **) NULL);
3185  }
3186  }
3187  } else if (argv[i][j] == 'w') {
3188  weighted = 1;
3189  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3190  weighted_param = (argv[i][j + 1] - '0');
3191  j++;
3192  }
3193  } else if (argv[i][j] == 'b') {
3194  // -b(brio_threshold/brio_ratio/hilbert_limit/hilbert_order)
3195  brio_hilbert = 1;
3196  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3197  (argv[i][j + 1] == '.')) {
3198  k = 0;
3199  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3200  (argv[i][j + 1] == '.')) {
3201  j++;
3202  workstring[k] = argv[i][j];
3203  k++;
3204  }
3205  workstring[k] = '\0';
3206  #pragma GCC diagnostic push
3207  #pragma GCC diagnostic ignored "-Wrestrict"
3208  brio_threshold = (int) strtol(workstring, (char **) &workstring, 0);
3209  #pragma GCC diagnostic pop
3210  }
3211  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3212  j++;
3213  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3214  (argv[i][j + 1] == '.')) {
3215  k = 0;
3216  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3217  (argv[i][j + 1] == '.')) {
3218  j++;
3219  workstring[k] = argv[i][j];
3220  k++;
3221  }
3222  workstring[k] = '\0';
3223  brio_ratio = (REAL) strtod(workstring, (char **) NULL);
3224  }
3225  }
3226  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3227  j++;
3228  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3229  (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3230  k = 0;
3231  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3232  (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3233  j++;
3234  workstring[k] = argv[i][j];
3235  k++;
3236  }
3237  workstring[k] = '\0';
3238  #pragma GCC diagnostic push
3239  #pragma GCC diagnostic ignored "-Wrestrict"
3240  hilbert_limit = (int) strtol(workstring, (char **) &workstring, 0);
3241  #pragma GCC diagnostic pop
3242  }
3243  }
3244  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3245  j++;
3246  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3247  (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3248  k = 0;
3249  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3250  (argv[i][j + 1] == '.') || (argv[i][j + 1] == '-')) {
3251  j++;
3252  workstring[k] = argv[i][j];
3253  k++;
3254  }
3255  workstring[k] = '\0';
3256  hilbert_order = (REAL) strtod(workstring, (char **) NULL);
3257  }
3258  }
3259  if (brio_threshold == 0) { // -b0
3260  brio_hilbert = 0; // Turn off BRIO-Hilbert sorting.
3261  }
3262  if (brio_ratio >= 1.0) { // -b/1
3263  no_sort = 1;
3264  brio_hilbert = 0; // Turn off BRIO-Hilbert sorting.
3265  }
3266  } else if (argv[i][j] == 'l') {
3267  incrflip = 1;
3268  } else if (argv[i][j] == 'L') {
3269  flipinsert = 1;
3270  } else if (argv[i][j] == 'm') {
3271  metric = 1;
3272  } else if (argv[i][j] == 'a') {
3273  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3274  (argv[i][j + 1] == '.')) {
3275  fixedvolume = 1;
3276  k = 0;
3277  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3278  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3279  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3280  j++;
3281  workstring[k] = argv[i][j];
3282  k++;
3283  }
3284  workstring[k] = '\0';
3285  maxvolume = (REAL) strtod(workstring, (char **) NULL);
3286  } else {
3287  varvolume = 1;
3288  }
3289  } else if (argv[i][j] == 'A') {
3290  regionattrib = 1;
3291  } else if (argv[i][j] == 'D') {
3292  cdtrefine = 1;
3293  if (argv[i][j + 1] == 'l') {
3294  use_equatorial_lens = 1;
3295  } else if ((argv[i][j + 1] >= '1') && (argv[i][j + 1] <= '3')) {
3296  reflevel = (argv[i][j + 1] - '1') + 1;
3297  j++;
3298  }
3299  } else if (argv[i][j] == 'i') {
3300  insertaddpoints = 1;
3301  } else if (argv[i][j] == 'd') {
3302  diagnose = 1;
3303  } else if (argv[i][j] == 'c') {
3304  convex = 1;
3305  } else if (argv[i][j] == 'M') {
3306  nomergefacet = 1;
3307  nomergevertex = 1;
3308  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
3309  nomergefacet = (argv[i][j + 1] - '0');
3310  j++;
3311  }
3312  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3313  j++;
3314  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '1')) {
3315  nomergevertex = (argv[i][j + 1] - '0');
3316  j++;
3317  }
3318  }
3319  } else if (argv[i][j] == 'X') {
3320  if (argv[i][j + 1] == '1') {
3321  nostaticfilter = 1;
3322  j++;
3323  } else {
3324  noexact = 1;
3325  }
3326  } else if (argv[i][j] == 'z') {
3327  if (argv[i][j + 1] == '1') { // -z1
3328  reversetetori = 1;
3329  j++;
3330  } else {
3331  zeroindex = 1; // -z
3332  }
3333  } else if (argv[i][j] == 'f') {
3334  facesout++;
3335  } else if (argv[i][j] == 'e') {
3336  edgesout++;
3337  } else if (argv[i][j] == 'n') {
3338  neighout++;
3339  } else if (argv[i][j] == 'v') {
3340  voroout = 1;
3341  } else if (argv[i][j] == 'g') {
3342  meditview = 1;
3343  } else if (argv[i][j] == 'k') {
3344  vtkview = 1;
3345  } else if (argv[i][j] == 'J') {
3346  nojettison = 1;
3347  } else if (argv[i][j] == 'B') {
3348  nobound = 1;
3349  } else if (argv[i][j] == 'N') {
3350  nonodewritten = 1;
3351  } else if (argv[i][j] == 'E') {
3352  noelewritten = 1;
3353  } else if (argv[i][j] == 'F') {
3354  nofacewritten = 1;
3355  } else if (argv[i][j] == 'I') {
3356  noiterationnum = 1;
3357  } else if (argv[i][j] == 'S') {
3358  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3359  (argv[i][j + 1] == '.')) {
3360  k = 0;
3361  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3362  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3363  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3364  j++;
3365  workstring[k] = argv[i][j];
3366  k++;
3367  }
3368  workstring[k] = '\0';
3369  steinerleft = (int) strtol(workstring, (char **) NULL, 0);
3370  }
3371  } else if (argv[i][j] == 'o') {
3372  if (argv[i][j + 1] == '2') {
3373  order = 2;
3374  j++;
3375  }
3376  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3377  j++;
3378  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3379  (argv[i][j + 1] == '.')) {
3380  k = 0;
3381  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3382  (argv[i][j + 1] == '.')) {
3383  j++;
3384  workstring[k] = argv[i][j];
3385  k++;
3386  }
3387  workstring[k] = '\0';
3388  optmaxdihedral = (REAL) strtod(workstring, (char **) NULL);
3389  }
3390  }
3391  } else if (argv[i][j] == 'O') {
3392  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) {
3393  optlevel = (argv[i][j + 1] - '0');
3394  j++;
3395  }
3396  if ((argv[i][j + 1] == '/') || (argv[i][j + 1] == ',')) {
3397  j++;
3398  if ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '7')) {
3399  optscheme = (argv[i][j + 1] - '0');
3400  j++;
3401  }
3402  }
3403  } else if (argv[i][j] == 'T') {
3404  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3405  (argv[i][j + 1] == '.')) {
3406  k = 0;
3407  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3408  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3409  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3410  j++;
3411  workstring[k] = argv[i][j];
3412  k++;
3413  }
3414  workstring[k] = '\0';
3415  epsilon = (REAL) strtod(workstring, (char **) NULL);
3416  }
3417  } else if (argv[i][j] == 'C') {
3418  docheck++;
3419  } else if (argv[i][j] == 'Q') {
3420  quiet = 1;
3421  } else if (argv[i][j] == 'V') {
3422  verbose++;
3423  } else if (argv[i][j] == 'x') {
3424  if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3425  (argv[i][j + 1] == '.')) {
3426  k = 0;
3427  while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
3428  (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') ||
3429  (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) {
3430  j++;
3431  workstring[k] = argv[i][j];
3432  k++;
3433  }
3434  workstring[k] = '\0';
3435  tetrahedraperblock = (int) strtol(workstring, (char **) NULL, 0);
3436  if (tetrahedraperblock > 8188) {
3437  vertexperblock = tetrahedraperblock / 2;
3438  shellfaceperblock = vertexperblock / 2;
3439  } else {
3440  tetrahedraperblock = 8188;
3441  }
3442  }
3443  } else if (argv[i][j] == 'H') {
3444  if (argv[i+1][0] != '-') {
3445  hole_mesh = 1;
3446  // It is a filename following by -H
3447  strncpy(hole_mesh_filename, argv[i+1], 1024 - 1);
3448  hole_mesh_filename[1024 - 1] = '\0';
3449  i++; // Skip the next string.
3450  break; // j
3451  }
3452  } else if (argv[i][j] == 'K') {
3453  apply_flow_bc = 1;
3454  } else if ((argv[i][j] == 'h') || // (argv[i][j] == 'H')
3455  (argv[i][j] == '?')) {
3456  usage();
3457  } else {
3458  printf("Warning: Unknown switch -%c.\n", argv[i][j]);
3459  }
3460  }
3461  }
3462 
3463  if (startindex == 0) {
3464  // Set a temporary filename for debugging output.
3465  strcpy(infilename, "tetgen-tmpfile");
3466  } else {
3467  if (infilename[0] == '\0') {
3468  // No input file name. Print the syntax and exit.
3469  syntax();
3470  terminatetetgen(NULL, 0);
3471  }
3472  // Recognize the object from file extension if it is available.
3473  if (!strcmp(&infilename[strlen(infilename) - 5], ".node")) {
3474  infilename[strlen(infilename) - 5] = '\0';
3475  object = NODES;
3476  } else if (!strcmp(&infilename[strlen(infilename) - 5], ".poly")) {
3477  infilename[strlen(infilename) - 5] = '\0';
3478  object = POLY;
3479  plc = 1;
3480  } else if (!strcmp(&infilename[strlen(infilename) - 6], ".smesh")) {
3481  infilename[strlen(infilename) - 6] = '\0';
3482  object = POLY;
3483  plc = 1;
3484  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".off")) {
3485  infilename[strlen(infilename) - 4] = '\0';
3486  object = OFF;
3487  plc = 1;
3488  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ply")) {
3489  infilename[strlen(infilename) - 4] = '\0';
3490  object = PLY;
3491  plc = 1;
3492  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".stl")) {
3493  infilename[strlen(infilename) - 4] = '\0';
3494  object = STL;
3495  plc = 1;
3496  } else if (!strcmp(&infilename[strlen(infilename) - 5], ".mesh")) {
3497  infilename[strlen(infilename) - 5] = '\0';
3498  object = MEDIT;
3499  if (!refine) plc = 1;
3500  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".vtk")) {
3501  infilename[strlen(infilename) - 4] = '\0';
3502  object = VTK;
3503  plc = 1;
3504  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ele")) {
3505  infilename[strlen(infilename) - 4] = '\0';
3506  object = MESH;
3507  refine = 1;
3508  } else if (!strcmp(&infilename[strlen(infilename) - 4], ".neu")) {
3509  infilename[strlen(infilename) - 4] = '\0';
3510  object = NEU_MESH;
3511  refine = 1;
3512  }
3513  }
3514 
3515  if (nobisect && (!plc && !refine)) { // -Y
3516  plc = 1; // Default -p option.
3517  }
3518  if (quality && (!plc && !refine)) { // -q
3519  plc = 1; // Default -p option.
3520  }
3521  if (diagnose && !plc) { // -d
3522  plc = 1;
3523  }
3524  if (refine && !quality) { // -r only
3525  // Reconstruct a mesh, no mesh optimization.
3526  optlevel = 0;
3527  }
3528  if (insertaddpoints && (optlevel == 0)) { // with -i option
3529  optlevel = 2;
3530  }
3531  if (coarsen && (optlevel == 0)) { // with -R option
3532  optlevel = 2;
3533  }
3534 
3535  // Detect improper combinations of switches.
3536  if ((refine || plc) && weighted) {
3537  printf("Error: Switches -w cannot use together with -p or -r.\n");
3538  return false;
3539  }
3540 
3541  if (convex) { // -c
3542  if (plc && !regionattrib) {
3543  // -A (region attribute) is needed for marking exterior tets (-1).
3544  regionattrib = 1;
3545  }
3546  }
3547 
3548  // Note: -A must not used together with -r option.
3549  // Be careful not to add an extra attribute to each element unless the
3550  // input supports it (PLC in, but not refining a preexisting mesh).
3551  if (refine || !plc) {
3552  regionattrib = 0;
3553  }
3554  // Be careful not to allocate space for element area constraints that
3555  // will never be assigned any value (other than the default -1.0).
3556  if (!refine && !plc) {
3557  varvolume = 0;
3558  }
3559  // If '-a' or '-aa' is in use, enable '-q' option too.
3560  if (fixedvolume || varvolume) {
3561  if (quality == 0) {
3562  quality = 1;
3563  if (!plc && !refine) {
3564  plc = 1; // enable -p.
3565  }
3566  }
3567  }
3568  // No user-specified dihedral angle bound. Use default ones.
3569  if (!quality) {
3570  if (optmaxdihedral < 179.0) {
3571  if (nobisect) { // with -Y option
3572  optmaxdihedral = 179.0;
3573  } else { // -p only
3574  optmaxdihedral = 179.999;
3575  }
3576  }
3577  if (optminsmtdihed < 179.999) {
3578  optminsmtdihed = 179.999;
3579  }
3580  if (optminslidihed < 179.999) {
3581  optminslidihed = 179.999;
3582  }
3583  }
3584 
3585  increment = 0;
3586  strcpy(workstring, infilename);
3587  j = 1;
3588  while (workstring[j] != '\0') {
3589  if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) {
3590  increment = j + 1;
3591  }
3592  j++;
3593  }
3594  meshnumber = 0;
3595  if (increment > 0) {
3596  j = increment;
3597  do {
3598  if ((workstring[j] >= '0') && (workstring[j] <= '9')) {
3599  meshnumber = meshnumber * 10 + (int) (workstring[j] - '0');
3600  } else {
3601  increment = 0;
3602  }
3603  j++;
3604  } while (workstring[j] != '\0');
3605  }
3606  if (noiterationnum) {
3607  strcpy(outfilename, infilename);
3608  } else if (increment == 0) {
3609  strcpy(outfilename, infilename);
3610  strcat(outfilename, ".1");
3611  } else {
3612  workstring[increment] = '%';
3613  workstring[increment + 1] = 'd';
3614  workstring[increment + 2] = '\0';
3615  sprintf(outfilename, workstring, meshnumber + 1);
3616  }
3617  // Additional input file name has the end ".a".
3618  strcpy(addinfilename, infilename);
3619  strcat(addinfilename, ".a");
3620  // Background filename has the form "*.b.ele", "*.b.node", ...
3621  strcpy(bgmeshfilename, infilename);
3622  strcat(bgmeshfilename, ".b");
3623 
3624  return true;
3625 }
3626 
3630 
3634 
3635 // Initialize fast lookup tables for mesh maniplulation primitives.
3636 
3637 int tetgenmesh::bondtbl[12][12] = {{0,},};
3638 int tetgenmesh::enexttbl[12] = {0,};
3639 int tetgenmesh::eprevtbl[12] = {0,};
3640 int tetgenmesh::enextesymtbl[12] = {0,};
3641 int tetgenmesh::eprevesymtbl[12] = {0,};
3642 int tetgenmesh::eorgoppotbl[12] = {0,};
3643 int tetgenmesh::edestoppotbl[12] = {0,};
3644 int tetgenmesh::fsymtbl[12][12] = {{0,},};
3645 int tetgenmesh::facepivot1[12] = {0,};
3646 int tetgenmesh::facepivot2[12][12] = {{0,},};
3647 int tetgenmesh::tsbondtbl[12][6] = {{0,},};
3648 int tetgenmesh::stbondtbl[12][6] = {{0,},};
3649 int tetgenmesh::tspivottbl[12][6] = {{0,},};
3650 int tetgenmesh::stpivottbl[12][6] = {{0,},};
3651 
3652 // Table 'esymtbl' takes an directed edge (version) as input, returns the
3653 // inversed edge (version) of it.
3654 
3655 int tetgenmesh::esymtbl[12] = {9, 6, 11, 4, 3, 7, 1, 5, 10, 0, 8, 2};
3656 
3657 // The following four tables give the 12 permutations of the set {0,1,2,3}.
3658 // An offset 4 is added to each element for a direct access of the points
3659 // in the tetrahedron data structure.
3660 
3661 int tetgenmesh:: orgpivot[12] = {7, 7, 5, 5, 6, 4, 4, 6, 5, 6, 7, 4};
3662 int tetgenmesh::destpivot[12] = {6, 4, 4, 6, 5, 6, 7, 4, 7, 7, 5, 5};
3663 int tetgenmesh::apexpivot[12] = {5, 6, 7, 4, 7, 7, 5, 5, 6, 4, 4, 6};
3664 int tetgenmesh::oppopivot[12] = {4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7};
3665 
3666 // The twelve versions correspond to six undirected edges. The following two
3667 // tables map a version to an undirected edge and vice versa.
3668 
3669 int tetgenmesh::ver2edge[12] = {0, 1, 2, 3, 3, 5, 1, 5, 4, 0, 4, 2};
3670 int tetgenmesh::edge2ver[ 6] = {0, 1, 2, 3, 8, 5};
3671 
3672 // Edge versions whose apex or opposite may be dummypoint.
3673 
3674 int tetgenmesh::epivot[12] = {4, 5, 2, 11, 4, 5, 2, 11, 4, 5, 2, 11};
3675 
3676 
3677 // Table 'snextpivot' takes an edge version as input, returns the next edge
3678 // version in the same edge ring.
3679 
3680 int tetgenmesh::snextpivot[6] = {2, 5, 4, 1, 0, 3};
3681 
3682 // The following three tables give the 6 permutations of the set {0,1,2}.
3683 // An offset 3 is added to each element for a direct access of the points
3684 // in the triangle data structure.
3685 
3686 int tetgenmesh::sorgpivot [6] = {3, 4, 4, 5, 5, 3};
3687 int tetgenmesh::sdestpivot[6] = {4, 3, 5, 4, 3, 5};
3688 int tetgenmesh::sapexpivot[6] = {5, 5, 3, 3, 4, 4};
3689 
3691 // //
3692 // inittable() Initialize the look-up tables. //
3693 // //
3695 
3696 void tetgenmesh::inittables()
3697 {
3698  int soffset, toffset;
3699  int i, j;
3700 
3701 
3702  // i = t1.ver; j = t2.ver;
3703  for (i = 0; i < 12; i++) {
3704  for (j = 0; j < 12; j++) {
3705  bondtbl[i][j] = (j & 3) + (((i & 12) + (j & 12)) % 12);
3706  }
3707  }
3708 
3709 
3710  // i = t1.ver; j = t2.ver
3711  for (i = 0; i < 12; i++) {
3712  for (j = 0; j < 12; j++) {
3713  fsymtbl[i][j] = (j + 12 - (i & 12)) % 12;
3714  }
3715  }
3716 
3717 
3718  for (i = 0; i < 12; i++) {
3719  facepivot1[i] = (esymtbl[i] & 3);
3720  }
3721 
3722  for (i = 0; i < 12; i++) {
3723  for (j = 0; j < 12; j++) {
3724  facepivot2[i][j] = fsymtbl[esymtbl[i]][j];
3725  }
3726  }
3727 
3728  for (i = 0; i < 12; i++) {
3729  enexttbl[i] = (i + 4) % 12;
3730  eprevtbl[i] = (i + 8) % 12;
3731  }
3732 
3733  for (i = 0; i < 12; i++) {
3734  enextesymtbl[i] = esymtbl[enexttbl[i]];
3735  eprevesymtbl[i] = esymtbl[eprevtbl[i]];
3736  }
3737 
3738  for (i = 0; i < 12; i++) {
3739  eorgoppotbl [i] = eprevtbl[esymtbl[enexttbl[i]]];
3740  edestoppotbl[i] = enexttbl[esymtbl[eprevtbl[i]]];
3741  }
3742 
3743  // i = t.ver, j = s.shver
3744  for (i = 0; i < 12; i++) {
3745  for (j = 0; j < 6; j++) {
3746  if ((j & 1) == 0) {
3747  soffset = (6 - ((i & 12) >> 1)) % 6;
3748  toffset = (12 - ((j & 6) << 1)) % 12;
3749  } else {
3750  soffset = (i & 12) >> 1;
3751  toffset = (j & 6) << 1;
3752  }
3753  tsbondtbl[i][j] = (j & 1) + (((j & 6) + soffset) % 6);
3754  stbondtbl[i][j] = (i & 3) + (((i & 12) + toffset) % 12);
3755  }
3756  }
3757 
3758 
3759  // i = t.ver, j = s.shver
3760  for (i = 0; i < 12; i++) {
3761  for (j = 0; j < 6; j++) {
3762  if ((j & 1) == 0) {
3763  soffset = (i & 12) >> 1;
3764  toffset = (j & 6) << 1;
3765  } else {
3766  soffset = (6 - ((i & 12) >> 1)) % 6;
3767  toffset = (12 - ((j & 6) << 1)) % 12;
3768  }
3769  tspivottbl[i][j] = (j & 1) + (((j & 6) + soffset) % 6);
3770  stpivottbl[i][j] = (i & 3) + (((i & 12) + toffset) % 12);
3771  }
3772  }
3773 }
3774 
3775 
3777 // //
3778 // restart() Deallocate all objects in this pool. //
3779 // //
3780 // The pool returns to a fresh state, like after it was initialized, except //
3781 // that no memory is freed to the operating system. Rather, the previously //
3782 // allocated blocks are ready to be used. //
3783 // //
3785 
3786 void tetgenmesh::arraypool::restart()
3787 {
3788  objects = 0l;
3789 }
3790 
3792 // //
3793 // poolinit() Initialize an arraypool for allocation of objects. //
3794 // //
3795 // Before the pool may be used, it must be initialized by this procedure. //
3796 // After initialization, memory can be allocated and freed in this pool. //
3797 // //
3799 
3800 void tetgenmesh::arraypool::poolinit(int sizeofobject, int log2objperblk)
3801 {
3802  // Each object must be at least one byte long.
3803  objectbytes = sizeofobject > 1 ? sizeofobject : 1;
3804 
3805  log2objectsperblock = log2objperblk;
3806  // Compute the number of objects in each block.
3807  objectsperblock = ((int) 1) << log2objectsperblock;
3808  objectsperblockmark = objectsperblock - 1;
3809 
3810  // No memory has been allocated.
3811  totalmemory = 0l;
3812  // The top array has not been allocated yet.
3813  toparray = (char **) NULL;
3814  toparraylen = 0;
3815 
3816  // Ready all indices to be allocated.
3817  restart();
3818 }
3819 
3821 // //
3822 // arraypool() The constructor and destructor. //
3823 // //
3825 
3826 tetgenmesh::arraypool::arraypool(int sizeofobject, int log2objperblk)
3827 {
3828  poolinit(sizeofobject, log2objperblk);
3829 }
3830 
3831 tetgenmesh::arraypool::~arraypool()
3832 {
3833  int i;
3834 
3835  // Has anything been allocated at all?
3836  if (toparray != (char **) NULL) {
3837  // Walk through the top array.
3838  for (i = 0; i < toparraylen; i++) {
3839  // Check every pointer; NULLs may be scattered randomly.
3840  if (toparray[i] != (char *) NULL) {
3841  // Free an allocated block.
3842  free((void *) toparray[i]);
3843  }
3844  }
3845  // Free the top array.
3846  free((void *) toparray);
3847  }
3848 
3849  // The top array is no longer allocated.
3850  toparray = (char **) NULL;
3851  toparraylen = 0;
3852  objects = 0;
3853  totalmemory = 0;
3854 }
3855 
3857 // //
3858 // getblock() Return (and perhaps create) the block containing the object //
3859 // with a given index. //
3860 // //
3861 // This function takes care of allocating or resizing the top array if nece- //
3862 // ssary, and of allocating the block if it hasn't yet been allocated. //
3863 // //
3864 // Return a pointer to the beginning of the block (NOT the object). //
3865 // //
3867 
3868 char* tetgenmesh::arraypool::getblock(int objectindex)
3869 {
3870  char **newarray;
3871  char *block;
3872  int newsize;
3873  int topindex;
3874  int i;
3875 
3876  // Compute the index in the top array (upper bits).
3877  topindex = objectindex >> log2objectsperblock;
3878  // Does the top array need to be allocated or resized?
3879  if (toparray == (char **) NULL) {
3880  // Allocate the top array big enough to hold 'topindex', and NULL out
3881  // its contents.
3882  newsize = topindex + 128;
3883  toparray = (char **) malloc((size_t) (newsize * sizeof(char *)));
3884  toparraylen = newsize;
3885  for (i = 0; i < newsize; i++) {
3886  toparray[i] = (char *) NULL;
3887  }
3888  // Account for the memory.
3889  totalmemory = newsize * (uintptr_t) sizeof(char *);
3890  } else if (topindex >= toparraylen) {
3891  // Resize the top array, making sure it holds 'topindex'.
3892  newsize = 3 * toparraylen;
3893  if (topindex >= newsize) {
3894  newsize = topindex + 128;
3895  }
3896  // Allocate the new array, copy the contents, NULL out the rest, and
3897  // free the old array.
3898  newarray = (char **) malloc((size_t) (newsize * sizeof(char *)));
3899  for (i = 0; i < toparraylen; i++) {
3900  newarray[i] = toparray[i];
3901  }
3902  for (i = toparraylen; i < newsize; i++) {
3903  newarray[i] = (char *) NULL;
3904  }
3905  free(toparray);
3906  // Account for the memory.
3907  totalmemory += (newsize - toparraylen) * sizeof(char *);
3908  toparray = newarray;
3909  toparraylen = newsize;
3910  }
3911 
3912  // Find the block, or learn that it hasn't been allocated yet.
3913  block = toparray[topindex];
3914  if (block == (char *) NULL) {
3915  // Allocate a block at this index.
3916  block = (char *) malloc((size_t) (objectsperblock * objectbytes));
3917  toparray[topindex] = block;
3918  // Account for the memory.
3919  totalmemory += objectsperblock * objectbytes;
3920  }
3921 
3922  // Return a pointer to the block.
3923  return block;
3924 }
3925 
3927 // //
3928 // lookup() Return the pointer to the object with a given index, or NULL //
3929 // if the object's block doesn't exist yet. //
3930 // //
3932 
3933 void* tetgenmesh::arraypool::lookup(int objectindex)
3934 {
3935  char *block;
3936  int topindex;
3937 
3938  // Has the top array been allocated yet?
3939  if (toparray == (char **) NULL) {
3940  return (void *) NULL;
3941  }
3942 
3943  // Compute the index in the top array (upper bits).
3944  topindex = objectindex >> log2objectsperblock;
3945  // Does the top index fit in the top array?
3946  if (topindex >= toparraylen) {
3947  return (void *) NULL;
3948  }
3949 
3950  // Find the block, or learn that it hasn't been allocated yet.
3951  block = toparray[topindex];
3952  if (block == (char *) NULL) {
3953  return (void *) NULL;
3954  }
3955 
3956  // Compute a pointer to the object with the given index. Note that
3957  // 'objectsperblock' is a power of two, so the & operation is a bit mask
3958  // that preserves the lower bits.
3959  return (void *)(block + (objectindex & (objectsperblock - 1)) * objectbytes);
3960 }
3961 
3963 // //
3964 // newindex() Allocate space for a fresh object from the pool. //
3965 // //
3966 // 'newptr' returns a pointer to the new object (it must not be a NULL). //
3967 // //
3969 
3970 int tetgenmesh::arraypool::newindex(void **newptr)
3971 {
3972  // Allocate an object at index 'firstvirgin'.
3973  int newindex = objects;
3974  *newptr = (void *) (getblock(objects) +
3975  (objects & (objectsperblock - 1)) * objectbytes);
3976  objects++;
3977 
3978  return newindex;
3979 }
3980 
3981 
3983 // //
3984 // memorypool() The constructors of memorypool. //
3985 // //
3987 
3988 tetgenmesh::memorypool::memorypool()
3989 {
3990  firstblock = nowblock = (void **) NULL;
3991  nextitem = (void *) NULL;
3992  deaditemstack = (void *) NULL;
3993  pathblock = (void **) NULL;
3994  pathitem = (void *) NULL;
3995  alignbytes = 0;
3996  itembytes = itemwords = 0;
3997  itemsperblock = 0;
3998  items = maxitems = 0l;
3999  unallocateditems = 0;
4000  pathitemsleft = 0;
4001 }
4002 
4003 tetgenmesh::memorypool::memorypool(int bytecount, int itemcount, int wsize,
4004  int alignment)
4005 {
4006  poolinit(bytecount, itemcount, wsize, alignment);
4007 }
4008 
4010 // //
4011 // ~memorypool() Free to the operating system all memory taken by a pool. //
4012 // //
4014 
4015 tetgenmesh::memorypool::~memorypool()
4016 {
4017  while (firstblock != (void **) NULL) {
4018  nowblock = (void **) *(firstblock);
4019  free(firstblock);
4020  firstblock = nowblock;
4021  }
4022 }
4023 
4025 // //
4026 // poolinit() Initialize a pool of memory for allocation of items. //
4027 // //
4028 // A `pool' is created whose records have size at least `bytecount'. Items //
4029 // will be allocated in `itemcount'-item blocks. Each item is assumed to be //
4030 // a collection of words, and either pointers or floating-point values are //
4031 // assumed to be the "primary" word type. (The "primary" word type is used //
4032 // to determine alignment of items.) If `alignment' isn't zero, all items //
4033 // will be `alignment'-byte aligned in memory. `alignment' must be either a //
4034 // multiple or a factor of the primary word size; powers of two are safe. //
4035 // `alignment' is normally used to create a few unused bits at the bottom of //
4036 // each item's pointer, in which information may be stored. //
4037 // //
4039 
4040 void tetgenmesh::memorypool::poolinit(int bytecount,int itemcount,int wordsize,
4041  int alignment)
4042 {
4043  // Find the proper alignment, which must be at least as large as:
4044  // - The parameter `alignment'.
4045  // - The primary word type, to avoid unaligned accesses.
4046  // - sizeof(void *), so the stack of dead items can be maintained
4047  // without unaligned accesses.
4048  if (alignment > wordsize) {
4049  alignbytes = alignment;
4050  } else {
4051  alignbytes = wordsize;
4052  }
4053  if ((int) sizeof(void *) > alignbytes) {
4054  alignbytes = (int) sizeof(void *);
4055  }
4056  itemwords = ((bytecount + alignbytes - 1) / alignbytes)
4057  * (alignbytes / wordsize);
4058  itembytes = itemwords * wordsize;
4059  itemsperblock = itemcount;
4060 
4061  // Allocate a block of items. Space for `itemsperblock' items and one
4062  // pointer (to point to the next block) are allocated, as well as space
4063  // to ensure alignment of the items.
4064  firstblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
4065  + alignbytes);
4066  if (firstblock == (void **) NULL) {
4067  terminatetetgen(NULL, 1);
4068  }
4069  // Set the next block pointer to NULL.
4070  *(firstblock) = (void *) NULL;
4071  restart();
4072 }
4073 
4075 // //
4076 // restart() Deallocate all items in this pool. //
4077 // //
4078 // The pool is returned to its starting state, except that no memory is //
4079 // freed to the operating system. Rather, the previously allocated blocks //
4080 // are ready to be reused. //
4081 // //
4083 
4084 void tetgenmesh::memorypool::restart()
4085 {
4086  uintptr_t alignptr;
4087 
4088  items = 0;
4089  maxitems = 0;
4090 
4091  // Set the currently active block.
4092  nowblock = firstblock;
4093  // Find the first item in the pool. Increment by the size of (void *).
4094  alignptr = (uintptr_t) (nowblock + 1);
4095  // Align the item on an `alignbytes'-byte boundary.
4096  nextitem = (void *)
4097  (alignptr + (uintptr_t) alignbytes -
4098  (alignptr % (uintptr_t) alignbytes));
4099  // There are lots of unallocated items left in this block.
4100  unallocateditems = itemsperblock;
4101  // The stack of deallocated items is empty.
4102  deaditemstack = (void *) NULL;
4103 }
4104 
4106 // //
4107 // alloc() Allocate space for an item. //
4108 // //
4110 
4111 void* tetgenmesh::memorypool::alloc()
4112 {
4113  void *newitem;
4114  void **newblock;
4115  uintptr_t alignptr;
4116 
4117  // First check the linked list of dead items. If the list is not
4118  // empty, allocate an item from the list rather than a fresh one.
4119  if (deaditemstack != (void *) NULL) {
4120  newitem = deaditemstack; // Take first item in list.
4121  deaditemstack = * (void **) deaditemstack;
4122  } else {
4123  // Check if there are any free items left in the current block.
4124  if (unallocateditems == 0) {
4125  // Check if another block must be allocated.
4126  if (*nowblock == (void *) NULL) {
4127  // Allocate a new block of items, pointed to by the previous block.
4128  newblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *)
4129  + alignbytes);
4130  if (newblock == (void **) NULL) {
4131  terminatetetgen(NULL, 1);
4132  }
4133  *nowblock = (void *) newblock;
4134  // The next block pointer is NULL.
4135  *newblock = (void *) NULL;
4136  }
4137  // Move to the new block.
4138  nowblock = (void **) *nowblock;
4139  // Find the first item in the block.
4140  // Increment by the size of (void *).
4141  alignptr = (uintptr_t) (nowblock + 1);
4142  // Align the item on an `alignbytes'-byte boundary.
4143  nextitem = (void *)
4144  (alignptr + (uintptr_t) alignbytes -
4145  (alignptr % (uintptr_t) alignbytes));
4146  // There are lots of unallocated items left in this block.
4147  unallocateditems = itemsperblock;
4148  }
4149  // Allocate a new item.
4150  newitem = nextitem;
4151  // Advance `nextitem' pointer to next free item in block.
4152  nextitem = (void *) ((uintptr_t) nextitem + itembytes);
4153  unallocateditems--;
4154  maxitems++;
4155  }
4156  items++;
4157  return newitem;
4158 }
4159 
4161 // //
4162 // dealloc() Deallocate space for an item. //
4163 // //
4164 // The deallocated space is stored in a queue for later reuse. //
4165 // //
4167 
4168 void tetgenmesh::memorypool::dealloc(void *dyingitem)
4169 {
4170  // Push freshly killed item onto stack.
4171  *((void **) dyingitem) = deaditemstack;
4172  deaditemstack = dyingitem;
4173  items--;
4174 }
4175 
4177 // //
4178 // traversalinit() Prepare to traverse the entire list of items. //
4179 // //
4180 // This routine is used in conjunction with traverse(). //
4181 // //
4183 
4184 void tetgenmesh::memorypool::traversalinit()
4185 {
4186  uintptr_t alignptr;
4187 
4188  // Begin the traversal in the first block.
4189  pathblock = firstblock;
4190  // Find the first item in the block. Increment by the size of (void *).
4191  alignptr = (uintptr_t) (pathblock + 1);
4192  // Align with item on an `alignbytes'-byte boundary.
4193  pathitem = (void *)
4194  (alignptr + (uintptr_t) alignbytes -
4195  (alignptr % (uintptr_t) alignbytes));
4196  // Set the number of items left in the current block.
4197  pathitemsleft = itemsperblock;
4198 }
4199 
4201 // //
4202 // traverse() Find the next item in the list. //
4203 // //
4204 // This routine is used in conjunction with traversalinit(). Be forewarned //
4205 // that this routine successively returns all items in the list, including //
4206 // deallocated ones on the deaditemqueue. It's up to you to figure out which //
4207 // ones are actually dead. It can usually be done more space-efficiently by //
4208 // a routine that knows something about the structure of the item. //
4209 // //
4211 
4212 void* tetgenmesh::memorypool::traverse()
4213 {
4214  void *newitem;
4215  uintptr_t alignptr;
4216 
4217  // Stop upon exhausting the list of items.
4218  if (pathitem == nextitem) {
4219  return (void *) NULL;
4220  }
4221  // Check whether any untraversed items remain in the current block.
4222  if (pathitemsleft == 0) {
4223  // Find the next block.
4224  pathblock = (void **) *pathblock;
4225  // Find the first item in the block. Increment by the size of (void *).
4226  alignptr = (uintptr_t) (pathblock + 1);
4227  // Align with item on an `alignbytes'-byte boundary.
4228  pathitem = (void *)
4229  (alignptr + (uintptr_t) alignbytes -
4230  (alignptr % (uintptr_t) alignbytes));
4231  // Set the number of items left in the current block.
4232  pathitemsleft = itemsperblock;
4233  }
4234  newitem = pathitem;
4235  // Find the next item in the block.
4236  pathitem = (void *) ((uintptr_t) pathitem + itembytes);
4237  pathitemsleft--;
4238  return newitem;
4239 }
4240 
4242 // //
4243 // makeindex2pointmap() Create a map from index to vertices. //
4244 // //
4245 // 'idx2verlist' returns the created map. Traverse all vertices, a pointer //
4246 // to each vertex is set into the array. The pointer to the first vertex is //
4247 // saved in 'idx2verlist[in->firstnumber]'. //
4248 // //
4250 
4251 void tetgenmesh::makeindex2pointmap(point*& idx2verlist)
4252 {
4253  point pointloop;
4254  int idx;
4255 
4256  if (b->verbose > 1) {
4257  printf(" Constructing mapping from indices to points.\n");
4258  }
4259 
4260  idx2verlist = new point[points->items + 1];
4261 
4262  points->traversalinit();
4263  pointloop = pointtraverse();
4264  idx = in->firstnumber;
4265  while (pointloop != (point) NULL) {
4266  idx2verlist[idx++] = pointloop;
4267  pointloop = pointtraverse();
4268  }
4269 }
4270 
4272 // //
4273 // makesubfacemap() Create a map from vertex to subfaces incident at it. //
4274 // //
4275 // The map is returned in two arrays 'idx2faclist' and 'facperverlist'. All //
4276 // subfaces incident at i-th vertex (i is counted from 0) are found in the //
4277 // array facperverlist[j], where idx2faclist[i] <= j < idx2faclist[i + 1]. //
4278 // Each entry in facperverlist[j] is a subface whose origin is the vertex. //
4279 // //
4280 // NOTE: These two arrays will be created inside this routine, don't forget //
4281 // to free them after using. //
4282 // //
4284 
4285 void tetgenmesh::makepoint2submap(memorypool* pool, int*& idx2faclist,
4286  face*& facperverlist)
4287 {
4288  face shloop;
4289  int i, j, k;
4290 
4291  if (b->verbose > 1) {
4292  printf(" Making a map from points to subfaces.\n");
4293  }
4294 
4295  // Initialize 'idx2faclist'.
4296  idx2faclist = new int[points->items + 1];
4297  for (i = 0; i < points->items + 1; i++) idx2faclist[i] = 0;
4298 
4299  // Loop all subfaces, counter the number of subfaces incident at a vertex.
4300  pool->traversalinit();
4301  shloop.sh = shellfacetraverse(pool);
4302  while (shloop.sh != (shellface *) NULL) {
4303  // Increment the number of incident subfaces for each vertex.
4304  j = pointmark((point) shloop.sh[3]) - in->firstnumber;
4305  idx2faclist[j]++;
4306  j = pointmark((point) shloop.sh[4]) - in->firstnumber;
4307  idx2faclist[j]++;
4308  // Skip the third corner if it is a segment.
4309  if (shloop.sh[5] != NULL) {
4310  j = pointmark((point) shloop.sh[5]) - in->firstnumber;
4311  idx2faclist[j]++;
4312  }
4313  shloop.sh = shellfacetraverse(pool);
4314  }
4315 
4316  // Calculate the total length of array 'facperverlist'.
4317  j = idx2faclist[0];
4318  idx2faclist[0] = 0; // Array starts from 0 element.
4319  for (i = 0; i < points->items; i++) {
4320  k = idx2faclist[i + 1];
4321  idx2faclist[i + 1] = idx2faclist[i] + j;
4322  j = k;
4323  }
4324 
4325  // The total length is in the last unit of idx2faclist.
4326  facperverlist = new face[idx2faclist[i]];
4327 
4328  // Loop all subfaces again, remember the subfaces at each vertex.
4329  pool->traversalinit();
4330  shloop.sh = shellfacetraverse(pool);
4331  while (shloop.sh != (shellface *) NULL) {
4332  j = pointmark((point) shloop.sh[3]) - in->firstnumber;
4333  shloop.shver = 0; // save the origin.
4334  facperverlist[idx2faclist[j]] = shloop;
4335  idx2faclist[j]++;
4336  // Is it a subface or a subsegment?
4337  if (shloop.sh[5] != NULL) {
4338  j = pointmark((point) shloop.sh[4]) - in->firstnumber;
4339  shloop.shver = 2; // save the origin.
4340  facperverlist[idx2faclist[j]] = shloop;
4341  idx2faclist[j]++;
4342  j = pointmark((point) shloop.sh[5]) - in->firstnumber;
4343  shloop.shver = 4; // save the origin.
4344  facperverlist[idx2faclist[j]] = shloop;
4345  idx2faclist[j]++;
4346  } else {
4347  j = pointmark((point) shloop.sh[4]) - in->firstnumber;
4348  shloop.shver = 1; // save the origin.
4349  facperverlist[idx2faclist[j]] = shloop;
4350  idx2faclist[j]++;
4351  }
4352  shloop.sh = shellfacetraverse(pool);
4353  }
4354 
4355  // Contents in 'idx2faclist' are shifted, now shift them back.
4356  for (i = points->items - 1; i >= 0; i--) {
4357  idx2faclist[i + 1] = idx2faclist[i];
4358  }
4359  idx2faclist[0] = 0;
4360 }
4361 
4363 // //
4364 // tetrahedrondealloc() Deallocate space for a tet., marking it dead. //
4365 // //
4367 
4368 void tetgenmesh::tetrahedrondealloc(tetrahedron *dyingtetrahedron)
4369 {
4370  // Set tetrahedron's vertices to NULL. This makes it possible to detect
4371  // dead tetrahedra when traversing the list of all tetrahedra.
4372  dyingtetrahedron[4] = (tetrahedron) NULL;
4373 
4374  // Dealloc the space to subfaces/subsegments.
4375  if (dyingtetrahedron[8] != NULL) {
4376  tet2segpool->dealloc((shellface *) dyingtetrahedron[8]);
4377  }
4378  if (dyingtetrahedron[9] != NULL) {
4379  tet2subpool->dealloc((shellface *) dyingtetrahedron[9]);
4380  }
4381 
4382  tetrahedrons->dealloc((void *) dyingtetrahedron);
4383 }
4384 
4386 // //
4387 // tetrahedrontraverse() Traverse the tetrahedra, skipping dead ones. //
4388 // //
4390 
4391 tetgenmesh::tetrahedron* tetgenmesh::tetrahedrontraverse()
4392 {
4393  tetrahedron *newtetrahedron;
4394 
4395  do {
4396  newtetrahedron = (tetrahedron *) tetrahedrons->traverse();
4397  if (newtetrahedron == (tetrahedron *) NULL) {
4398  return (tetrahedron *) NULL;
4399  }
4400  } while ((newtetrahedron[4] == (tetrahedron) NULL) ||
4401  ((point) newtetrahedron[7] == dummypoint));
4402  return newtetrahedron;
4403 }
4404 
4405 tetgenmesh::tetrahedron* tetgenmesh::alltetrahedrontraverse()
4406 {
4407  tetrahedron *newtetrahedron;
4408 
4409  do {
4410  newtetrahedron = (tetrahedron *) tetrahedrons->traverse();
4411  if (newtetrahedron == (tetrahedron *) NULL) {
4412  return (tetrahedron *) NULL;
4413  }
4414  } while (newtetrahedron[4] == (tetrahedron) NULL); // Skip dead ones.
4415  return newtetrahedron;
4416 }
4417 
4419 // //
4420 // shellfacedealloc() Deallocate space for a shellface, marking it dead. //
4421 // Used both for dealloc a subface and subsegment. //
4422 // //
4424 
4425 void tetgenmesh::shellfacedealloc(memorypool *pool, shellface *dyingsh)
4426 {
4427  // Set shellface's vertices to NULL. This makes it possible to detect dead
4428  // shellfaces when traversing the list of all shellfaces.
4429  dyingsh[3] = (shellface) NULL;
4430  pool->dealloc((void *) dyingsh);
4431 }
4432 
4434 // //
4435 // shellfacetraverse() Traverse the subfaces, skipping dead ones. Used //
4436 // for both subfaces and subsegments pool traverse. //
4437 // //
4439 
4440 tetgenmesh::shellface* tetgenmesh::shellfacetraverse(memorypool *pool)
4441 {
4442  shellface *newshellface;
4443 
4444  do {
4445  newshellface = (shellface *) pool->traverse();
4446  if (newshellface == (shellface *) NULL) {
4447  return (shellface *) NULL;
4448  }
4449  } while (newshellface[3] == (shellface) NULL); // Skip dead ones.
4450  return newshellface;
4451 }
4452 
4453 
4455 // //
4456 // pointdealloc() Deallocate space for a point, marking it dead. //
4457 // //
4459 
4460 void tetgenmesh::pointdealloc(point dyingpoint)
4461 {
4462  // Mark the point as dead. This makes it possible to detect dead points
4463  // when traversing the list of all points.
4464  setpointtype(dyingpoint, DEADVERTEX);
4465  points->dealloc((void *) dyingpoint);
4466 }
4467 
4469 // //
4470 // pointtraverse() Traverse the points, skipping dead ones. //
4471 // //
4473 
4474 tetgenmesh::point tetgenmesh::pointtraverse()
4475 {
4476  point newpoint;
4477 
4478  do {
4479  newpoint = (point) points->traverse();
4480  if (newpoint == (point) NULL) {
4481  return (point) NULL;
4482  }
4483  } while (pointtype(newpoint) == DEADVERTEX); // Skip dead ones.
4484  return newpoint;
4485 }
4486 
4488 // //
4489 // maketetrahedron() Create a new tetrahedron. //
4490 // //
4492 
4493 void tetgenmesh::maketetrahedron(triface *newtet)
4494 {
4495  newtet->tet = (tetrahedron *) tetrahedrons->alloc();
4496 
4497  // Initialize the four adjoining tetrahedra to be "outer space".
4498  newtet->tet[0] = NULL;
4499  newtet->tet[1] = NULL;
4500  newtet->tet[2] = NULL;
4501  newtet->tet[3] = NULL;
4502  // Four NULL vertices.
4503  newtet->tet[4] = NULL;
4504  newtet->tet[5] = NULL;
4505  newtet->tet[6] = NULL;
4506  newtet->tet[7] = NULL;
4507  // No attached segments and subfaces yet.
4508  newtet->tet[8] = NULL;
4509  newtet->tet[9] = NULL;
4510  // Initialize the marker (clear all flags).
4511  setelemmarker(newtet->tet, 0);
4512  for (int i = 0; i < numelemattrib; i++) {
4513  setelemattribute(newtet->tet, i, 0.0);
4514  }
4515  if (b->varvolume) {
4516  setvolumebound(newtet->tet, -1.0);
4517  }
4518 
4519  // Initialize the version to be Zero.
4520  newtet->ver = 11;
4521 }
4522 
4524 // //
4525 // makeshellface() Create a new shellface with version zero. Used for //
4526 // both subfaces and subsegments. //
4527 // //
4529 
4530 void tetgenmesh::makeshellface(memorypool *pool, face *newface)
4531 {
4532  newface->sh = (shellface *) pool->alloc();
4533 
4534  // No adjointing subfaces.
4535  newface->sh[0] = NULL;
4536  newface->sh[1] = NULL;
4537  newface->sh[2] = NULL;
4538  // Three NULL vertices.
4539  newface->sh[3] = NULL;
4540  newface->sh[4] = NULL;
4541  newface->sh[5] = NULL;
4542  // No adjoining subsegments.
4543  newface->sh[6] = NULL;
4544  newface->sh[7] = NULL;
4545  newface->sh[8] = NULL;
4546  // No adjoining tetrahedra.
4547  newface->sh[9] = NULL;
4548  newface->sh[10] = NULL;
4549  if (checkconstraints) {
4550  // Initialize the maximum area bound.
4551  setareabound(*newface, 0.0);
4552  }
4553  // Set the boundary marker to zero.
4554  setshellmark(*newface, 0);
4555  // Clear the infection and marktest bits.
4556  ((int *) (newface->sh))[shmarkindex + 1] = 0;
4557  if (useinsertradius) {
4558  setfacetindex(*newface, 0);
4559  }
4560 
4561  newface->shver = 0;
4562 }
4563 
4565 // //
4566 // makepoint() Create a new point. //
4567 // //
4569 
4570 void tetgenmesh::makepoint(point* pnewpoint, enum verttype vtype)
4571 {
4572  int i;
4573 
4574  *pnewpoint = (point) points->alloc();
4575 
4576  // Initialize the point attributes.
4577  for (i = 0; i < numpointattrib; i++) {
4578  (*pnewpoint)[3 + i] = 0.0;
4579  }
4580  // Initialize the metric tensor.
4581  for (i = 0; i < sizeoftensor; i++) {
4582  (*pnewpoint)[pointmtrindex + i] = 0.0;
4583  }
4584  setpoint2tet(*pnewpoint, NULL);
4585  setpoint2ppt(*pnewpoint, NULL);
4586  if (b->plc || b->refine) {
4587  // Initialize the point-to-simplex field.
4588  setpoint2sh(*pnewpoint, NULL);
4589  if (b->metric && (bgm != NULL)) {
4590  setpoint2bgmtet(*pnewpoint, NULL);
4591  }
4592  }
4593  // Initialize the point marker (starting from in->firstnumber).
4594  setpointmark(*pnewpoint, (int) (points->items) - (!in->firstnumber));
4595  // Clear all flags.
4596  ((int *) (*pnewpoint))[pointmarkindex + 1] = 0;
4597  // Initialize (set) the point type.
4598  setpointtype(*pnewpoint, vtype);
4599 }
4600 
4602 // //
4603 // initializepools() Calculate the sizes of the point, tetrahedron, and //
4604 // subface. Initialize their memory pools. //
4605 // //
4606 // This routine also computes the indices 'pointmarkindex', 'point2simindex',//
4607 // 'point2pbcptindex', 'elemattribindex', and 'volumeboundindex'. They are //
4608 // used to find values within each point and tetrahedron, respectively. //
4609 // //
4611 
4612 void tetgenmesh::initializepools()
4613 {
4614  int pointsize = 0, elesize = 0, shsize = 0;
4615  int i;
4616 
4617  if (b->verbose) {
4618  printf(" Initializing memorypools.\n");
4619  printf(" tetrahedron per block: %d.\n", b->tetrahedraperblock);
4620  }
4621 
4622  inittables();
4623 
4624  // There are three input point lists available, which are in, addin,
4625  // and bgm->in. These point lists may have different number of
4626  // attributes. Decide the maximum number.
4627  numpointattrib = in->numberofpointattributes;
4628  if (bgm != NULL) {
4629  if (bgm->in->numberofpointattributes > numpointattrib) {
4630  numpointattrib = bgm->in->numberofpointattributes;
4631  }
4632  }
4633  if (addin != NULL) {
4634  if (addin->numberofpointattributes > numpointattrib) {
4635  numpointattrib = addin->numberofpointattributes;
4636  }
4637  }
4638  if (b->weighted || b->flipinsert) { // -w or -L.
4639  // The internal number of point attribute needs to be at least 1
4640  // (for storing point weights).
4641  if (numpointattrib == 0) {
4642  numpointattrib = 1;
4643  }
4644  }
4645 
4646  // Default varconstraint = 0;
4647  if (in->segmentconstraintlist || in->facetconstraintlist) {
4648  checkconstraints = 1;
4649  }
4650  if (b->plc || b->refine) {
4651  // Save the insertion radius for Steiner points if boundaries
4652  // are allowed be split.
4653  if (!b->nobisect || checkconstraints) {
4654  useinsertradius = 1;
4655  }
4656  }
4657 
4658  // The index within each point at which its metric tensor is found.
4659  // Each vertex has three coordinates.
4660  if (b->psc) {
4661  // '-s' option (PSC), the u,v coordinates are provided.
4662  pointmtrindex = 5 + numpointattrib;
4663  // The index within each point at which its u, v coordinates are found.
4664  // Comment: They are saved after the list of point attributes.
4665  pointparamindex = pointmtrindex - 2;
4666  } else {
4667  pointmtrindex = 3 + numpointattrib;
4668  }
4669  // For '-m' option. A tensor field is provided (*.mtr or *.b.mtr file).
4670  if (b->metric) {
4671  // Decide the size (1, 3, or 6) of the metric tensor.
4672  if (bgm != (tetgenmesh *) NULL) {
4673  // A background mesh is allocated. It may not exist though.
4674  sizeoftensor = (bgm->in != (tetgenio *) NULL) ?
4675  bgm->in->numberofpointmtrs : in->numberofpointmtrs;
4676  } else {
4677  // No given background mesh - Itself is a background mesh.
4678  sizeoftensor = in->numberofpointmtrs;
4679  }
4680  // Make sure sizeoftensor is at least 1.
4681  sizeoftensor = (sizeoftensor > 0) ? sizeoftensor : 1;
4682  } else {
4683  // For '-q' option. Make sure to have space for saving a scalar value.
4684  sizeoftensor = b->quality ? 1 : 0;
4685  }
4686  if (useinsertradius) {
4687  // Increase a space (REAL) for saving point insertion radius, it is
4688  // saved directly after the metric.
4689  sizeoftensor++;
4690  }
4691  pointinsradiusindex = pointmtrindex + sizeoftensor - 1;
4692  // The index within each point at which an element pointer is found, where
4693  // the index is measured in pointers. Ensure the index is aligned to a
4694  // sizeof(tetrahedron)-byte address.
4695  point2simindex = ((pointmtrindex + sizeoftensor) * sizeof(REAL)
4696  + sizeof(tetrahedron) - 1) / sizeof(tetrahedron);
4697  if (b->plc || b->refine || b->voroout) {
4698  // Increase the point size by three pointers, which are:
4699  // - a pointer to a tet, read by point2tet();
4700  // - a pointer to a parent point, read by point2ppt()).
4701  // - a pointer to a subface or segment, read by point2sh();
4702  if (b->metric && (bgm != (tetgenmesh *) NULL)) {
4703  // Increase one pointer into the background mesh, point2bgmtet().
4704  pointsize = (point2simindex + 4) * sizeof(tetrahedron);
4705  } else {
4706  pointsize = (point2simindex + 3) * sizeof(tetrahedron);
4707  }
4708  } else {
4709  // Increase the point size by two pointer, which are:
4710  // - a pointer to a tet, read by point2tet();
4711  // - a pointer to a parent point, read by point2ppt()). -- Used by btree.
4712  pointsize = (point2simindex + 2) * sizeof(tetrahedron);
4713  }
4714  // The index within each point at which the boundary marker is found,
4715  // Ensure the point marker is aligned to a sizeof(int)-byte address.
4716  pointmarkindex = (pointsize + sizeof(int) - 1) / sizeof(int);
4717  // Now point size is the ints (indicated by pointmarkindex) plus:
4718  // - an integer for boundary marker;
4719  // - an integer for vertex type;
4720  // - an integer for geometry tag (optional, -s option).
4721  pointsize = (pointmarkindex + 2 + (b->psc ? 1 : 0)) * sizeof(tetrahedron);
4722 
4723  // Initialize the pool of vertices.
4724  points = new memorypool(pointsize, b->vertexperblock, sizeof(REAL), 0);
4725 
4726  if (b->verbose) {
4727  printf(" Size of a point: %d bytes.\n", points->itembytes);
4728  }
4729 
4730  // Initialize the infinite vertex.
4731  dummypoint = (point) new char[pointsize];
4732  // Initialize all fields of this point.
4733  dummypoint[0] = 0.0;
4734  dummypoint[1] = 0.0;
4735  dummypoint[2] = 0.0;
4736  for (i = 0; i < numpointattrib; i++) {
4737  dummypoint[3 + i] = 0.0;
4738  }
4739  // Initialize the metric tensor.
4740  for (i = 0; i < sizeoftensor; i++) {
4741  dummypoint[pointmtrindex + i] = 0.0;
4742  }
4743  setpoint2tet(dummypoint, NULL);
4744  setpoint2ppt(dummypoint, NULL);
4745  if (b->plc || b->psc || b->refine) {
4746  // Initialize the point-to-simplex field.
4747  setpoint2sh(dummypoint, NULL);
4748  if (b->metric && (bgm != NULL)) {
4749  setpoint2bgmtet(dummypoint, NULL);
4750  }
4751  }
4752  // Initialize the point marker (starting from in->firstnumber).
4753  setpointmark(dummypoint, -1); // The unique marker for dummypoint.
4754  // Clear all flags.
4755  ((int *) (dummypoint))[pointmarkindex + 1] = 0;
4756  // Initialize (set) the point type.
4757  setpointtype(dummypoint, UNUSEDVERTEX); // Does not matter.
4758 
4759  // The number of bytes occupied by a tetrahedron is varying by the user-
4760  // specified options. The contents of the first 12 pointers are listed
4761  // in the following table:
4762  // [0] |__ neighbor at f0 __|
4763  // [1] |__ neighbor at f1 __|
4764  // [2] |__ neighbor at f2 __|
4765  // [3] |__ neighbor at f3 __|
4766  // [4] |_____ vertex p0 ____|
4767  // [5] |_____ vertex p1 ____|
4768  // [6] |_____ vertex p2 ____|
4769  // [7] |_____ vertex p3 ____|
4770  // [8] |__ segments array __| (used by -p)
4771  // [9] |__ subfaces array __| (used by -p)
4772  // [10] |_____ reserved _____|
4773  // [11] |___ elem marker ____| (used as an integer)
4774 
4775  elesize = 12 * sizeof(tetrahedron);
4776 
4777  // The index to find the element markers. An integer containing varies
4778  // flags and element counter.
4779  if (!(sizeof(int) <= sizeof(tetrahedron)) ||
4780  ((sizeof(tetrahedron) % sizeof(int)))) {
4781  terminatetetgen(this, 2);
4782  }
4783  elemmarkerindex = (elesize - sizeof(tetrahedron)) / sizeof(int);
4784 
4785  // The actual number of element attributes. Note that if the
4786  // `b->regionattrib' flag is set, an additional attribute will be added.
4787  numelemattrib = in->numberoftetrahedronattributes + (b->regionattrib > 0);
4788 
4789  // The index within each element at which its attributes are found, where
4790  // the index is measured in REALs.
4791  elemattribindex = (elesize + sizeof(REAL) - 1) / sizeof(REAL);
4792  // The index within each element at which the maximum volume bound is
4793  // found, where the index is measured in REALs.
4794  volumeboundindex = elemattribindex + numelemattrib;
4795  // If element attributes or an constraint are needed, increase the number
4796  // of bytes occupied by an element.
4797  if (b->varvolume) {
4798  elesize = (volumeboundindex + 1) * sizeof(REAL);
4799  } else if (numelemattrib > 0) {
4800  elesize = volumeboundindex * sizeof(REAL);
4801  }
4802 
4803 
4804  // Having determined the memory size of an element, initialize the pool.
4805  tetrahedrons = new memorypool(elesize, b->tetrahedraperblock, sizeof(void *),
4806  16);
4807 
4808  if (b->verbose) {
4809  printf(" Size of a tetrahedron: %d (%d) bytes.\n", elesize,
4810  tetrahedrons->itembytes);
4811  }
4812 
4813  if (b->plc || b->refine) { // if (b->useshelles) {
4814  // The number of bytes occupied by a subface. The list of pointers
4815  // stored in a subface are: three to other subfaces, three to corners,
4816  // three to subsegments, two to tetrahedra.
4817  shsize = 11 * sizeof(shellface);
4818  // The index within each subface at which the maximum area bound is
4819  // found, where the index is measured in REALs.
4820  areaboundindex = (shsize + sizeof(REAL) - 1) / sizeof(REAL);
4821  // If -q switch is in use, increase the number of bytes occupied by
4822  // a subface for saving maximum area bound.
4823  if (checkconstraints) {
4824  shsize = (areaboundindex + 1) * sizeof(REAL);
4825  } else {
4826  shsize = areaboundindex * sizeof(REAL);
4827  }
4828  // The index within subface at which the facet marker is found. Ensure
4829  // the marker is aligned to a sizeof(int)-byte address.
4830  shmarkindex = (shsize + sizeof(int) - 1) / sizeof(int);
4831  // Increase the number of bytes by two or three integers, one for facet
4832  // marker, one for shellface type and flags, and optionally one
4833  // for storing facet index (for mesh refinement).
4834  shsize = (shmarkindex + 2 + useinsertradius) * sizeof(shellface);
4835 
4836  // Initialize the pool of subfaces. Each subface record is eight-byte
4837  // aligned so it has room to store an edge version (from 0 to 5) in
4838  // the least three bits.
4839  subfaces = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8);
4840 
4841  if (b->verbose) {
4842  printf(" Size of a shellface: %d (%d) bytes.\n", shsize,
4843  subfaces->itembytes);
4844  }
4845 
4846  // Initialize the pool of subsegments. The subsegment's record is same
4847  // with subface.
4848  subsegs = new memorypool(shsize, b->shellfaceperblock, sizeof(void *), 8);
4849 
4850  // Initialize the pool for tet-subseg connections.
4851  tet2segpool = new memorypool(6 * sizeof(shellface), b->shellfaceperblock,
4852  sizeof(void *), 0);
4853  // Initialize the pool for tet-subface connections.
4854  tet2subpool = new memorypool(4 * sizeof(shellface), b->shellfaceperblock,
4855  sizeof(void *), 0);
4856 
4857  // Initialize arraypools for segment & facet recovery.
4858  subsegstack = new arraypool(sizeof(face), 10);
4859  subfacstack = new arraypool(sizeof(face), 10);
4860  subvertstack = new arraypool(sizeof(point), 8);
4861 
4862  // Initialize arraypools for surface point insertion/deletion.
4863  caveshlist = new arraypool(sizeof(face), 8);
4864  caveshbdlist = new arraypool(sizeof(face), 8);
4865  cavesegshlist = new arraypool(sizeof(face), 4);
4866 
4867  cavetetshlist = new arraypool(sizeof(face), 8);
4868  cavetetseglist = new arraypool(sizeof(face), 8);
4869  caveencshlist = new arraypool(sizeof(face), 8);
4870  caveencseglist = new arraypool(sizeof(face), 8);
4871  }
4872 
4873  // Initialize the pools for flips.
4874  flippool = new memorypool(sizeof(badface), 1024, sizeof(void *), 0);
4875  unflipqueue = new arraypool(sizeof(badface), 10);
4876 
4877  // Initialize the arraypools for point insertion.
4878  cavetetlist = new arraypool(sizeof(triface), 10);
4879  cavebdrylist = new arraypool(sizeof(triface), 10);
4880  caveoldtetlist = new arraypool(sizeof(triface), 10);
4881  cavetetvertlist = new arraypool(sizeof(point), 10);
4882 }
4883 
4887 
4891 
4892 // PI is the ratio of a circle's circumference to its diameter.
4893 REAL tetgenmesh::PI = 3.14159265358979323846264338327950288419716939937510582;
4894 
4896 // //
4897 // insphere_s() Insphere test with symbolic perturbation. //
4898 // //
4899 // Given four points pa, pb, pc, and pd, test if the point pe lies inside or //
4900 // outside the circumscribed sphere of the four points. //
4901 // //
4902 // Here we assume that the 3d orientation of the point sequence {pa, pb, pc, //
4903 // pd} is positive (NOT zero), i.e., pd lies above the plane passing through //
4904 // points pa, pb, and pc. Otherwise, the returned sign is flipped. //
4905 // //
4906 // Return a positive value (> 0) if pe lies inside, a negative value (< 0) //
4907 // if pe lies outside the sphere, the returned value will not be zero. //
4908 // //
4910 
4911 REAL tetgenmesh::insphere_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe)
4912 {
4913  REAL sign;
4914 
4915  sign = insphere(pa, pb, pc, pd, pe);
4916  if (sign != 0.0) {
4917  return sign;
4918  }
4919 
4920  // Symbolic perturbation.
4921  point pt[5], swappt;
4922  REAL oriA, oriB;
4923  int swaps, count;
4924  int n, i;
4925 
4926  pt[0] = pa;
4927  pt[1] = pb;
4928  pt[2] = pc;
4929  pt[3] = pd;
4930  pt[4] = pe;
4931 
4932  // Sort the five points such that their indices are in the increasing
4933  // order. An optimized bubble sort algorithm is used, i.e., it has
4934  // the worst case O(n^2) runtime, but it is usually much faster.
4935  swaps = 0; // Record the total number of swaps.
4936  n = 5;
4937  do {
4938  count = 0;
4939  n = n - 1;
4940  for (i = 0; i < n; i++) {
4941  if (pointmark(pt[i]) > pointmark(pt[i+1])) {
4942  swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt;
4943  count++;
4944  }
4945  }
4946  swaps += count;
4947  } while (count > 0); // Continue if some points are swapped.
4948 
4949  oriA = orient3d(pt[1], pt[2], pt[3], pt[4]);
4950  if (oriA != 0.0) {
4951  // Flip the sign if there are odd number of swaps.
4952  if ((swaps % 2) != 0) oriA = -oriA;
4953  return oriA;
4954  }
4955 
4956  oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]);
4957  if (oriB == 0.0) {
4958  terminatetetgen(this, 2);
4959  }
4960  // Flip the sign if there are odd number of swaps.
4961  if ((swaps % 2) != 0) oriB = -oriB;
4962  return oriB;
4963 }
4964 
4966 // //
4967 // orient4d_s() 4d orientation test with symbolic perturbation. //
4968 // //
4969 // Given four lifted points pa', pb', pc', and pd' in R^4,test if the lifted //
4970 // point pe' in R^4 lies below or above the hyperplane passing through the //
4971 // four points pa', pb', pc', and pd'. //
4972 // //
4973 // Here we assume that the 3d orientation of the point sequence {pa, pb, pc, //
4974 // pd} is positive (NOT zero), i.e., pd lies above the plane passing through //
4975 // the points pa, pb, and pc. Otherwise, the returned sign is flipped. //
4976 // //
4977 // Return a positive value (> 0) if pe' lies below, a negative value (< 0) //
4978 // if pe' lies above the hyperplane, the returned value should not be zero. //
4979 // //
4981 
4982 REAL tetgenmesh::orient4d_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe,
4983  REAL aheight, REAL bheight, REAL cheight,
4984  REAL dheight, REAL eheight)
4985 {
4986  REAL sign;
4987 
4988  sign = orient4d(pa, pb, pc, pd, pe,
4989  aheight, bheight, cheight, dheight, eheight);
4990  if (sign != 0.0) {
4991  return sign;
4992  }
4993 
4994  // Symbolic perturbation.
4995  point pt[5], swappt;
4996  REAL oriA, oriB;
4997  int swaps, count;
4998  int n, i;
4999 
5000  pt[0] = pa;
5001  pt[1] = pb;
5002  pt[2] = pc;
5003  pt[3] = pd;
5004  pt[4] = pe;
5005 
5006  // Sort the five points such that their indices are in the increasing
5007  // order. An optimized bubble sort algorithm is used, i.e., it has
5008  // the worst case O(n^2) runtime, but it is usually much faster.
5009  swaps = 0; // Record the total number of swaps.
5010  n = 5;
5011  do {
5012  count = 0;
5013  n = n - 1;
5014  for (i = 0; i < n; i++) {
5015  if (pointmark(pt[i]) > pointmark(pt[i+1])) {
5016  swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt;
5017  count++;
5018  }
5019  }
5020  swaps += count;
5021  } while (count > 0); // Continue if some points are swapped.
5022 
5023  oriA = orient3d(pt[1], pt[2], pt[3], pt[4]);
5024  if (oriA != 0.0) {
5025  // Flip the sign if there are odd number of swaps.
5026  if ((swaps % 2) != 0) oriA = -oriA;
5027  return oriA;
5028  }
5029 
5030  oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]);
5031  if (oriB == 0.0) {
5032  terminatetetgen(this, 2);
5033  }
5034  // Flip the sign if there are odd number of swaps.
5035  if ((swaps % 2) != 0) oriB = -oriB;
5036  return oriB;
5037 }
5038 
5040 // //
5041 // tri_edge_test() Triangle-edge intersection test. //
5042 // //
5043 // This routine takes a triangle T (with vertices A, B, C) and an edge E (P, //
5044 // Q) in 3D, and tests if they intersect each other. //
5045 // //
5046 // If the point 'R' is not NULL, it lies strictly above the plane defined by //
5047 // A, B, C. It is used in test when T and E are coplanar. //
5048 // //
5049 // If T and E intersect each other, they may intersect in different ways. If //
5050 // 'level' > 0, their intersection type will be reported 'types' and 'pos'. //
5051 // //
5052 // The return value indicates one of the following cases: //
5053 // - 0, T and E are disjoint. //
5054 // - 1, T and E intersect each other. //
5055 // - 2, T and E are not coplanar. They intersect at a single point. //
5056 // - 4, T and E are coplanar. They intersect at a single point or a line //
5057 // segment (if types[1] != DISJOINT). //
5058 // //
5060 
5061 #define SETVECTOR3(V, a0, a1, a2) (V)[0] = (a0); (V)[1] = (a1); (V)[2] = (a2)
5062 
5063 #define SWAP2(a0, a1, tmp) (tmp) = (a0); (a0) = (a1); (a1) = (tmp)
5064 
5065 int tetgenmesh::tri_edge_2d(point A, point B, point C, point P, point Q,
5066  point R, int level, int *types, int *pos)
5067 {
5068  point U[3], V[3]; // The permuted vectors of points.
5069  int pu[3], pv[3]; // The original positions of points.
5070  REAL abovept[3];
5071  REAL sA, sB, sC;
5072  REAL s1, s2, s3, s4;
5073  int z1;
5074 
5075  if (R == NULL) {
5076  // Calculate a lift point.
5077  if (1) {
5078  REAL n[3], len;
5079  // Calculate a lift point, saved in dummypoint.
5080  facenormal(A, B, C, n, 1, NULL);
5081  len = sqrt(dot(n, n));
5082  if (len != 0) {
5083  n[0] /= len;
5084  n[1] /= len;
5085  n[2] /= len;
5086  len = distance(A, B);
5087  len += distance(B, C);
5088  len += distance(C, A);
5089  len /= 3.0;
5090  R = abovept; //dummypoint;
5091  R[0] = A[0] + len * n[0];
5092  R[1] = A[1] + len * n[1];
5093  R[2] = A[2] + len * n[2];
5094  } else {
5095  // The triangle [A,B,C] is (nearly) degenerate, i.e., it is (close)
5096  // to a line. We need a line-line intersection test.
5097  // !!! A non-save return value.!!!
5098  return 0; // DISJOINT
5099  }
5100  }
5101  }
5102 
5103  // Test A's, B's, and C's orientations wrt plane PQR.
5104  sA = orient3d(P, Q, R, A);
5105  sB = orient3d(P, Q, R, B);
5106  sC = orient3d(P, Q, R, C);
5107 
5108 
5109  if (sA < 0) {
5110  if (sB < 0) {
5111  if (sC < 0) { // (---).
5112  return 0;
5113  } else {
5114  if (sC > 0) { // (--+).
5115  // All points are in the right positions.
5116  SETVECTOR3(U, A, B, C); // I3
5117  SETVECTOR3(V, P, Q, R); // I2
5118  SETVECTOR3(pu, 0, 1, 2);
5119  SETVECTOR3(pv, 0, 1, 2);
5120  z1 = 0;
5121  } else { // (--0).
5122  SETVECTOR3(U, A, B, C); // I3
5123  SETVECTOR3(V, P, Q, R); // I2
5124  SETVECTOR3(pu, 0, 1, 2);
5125  SETVECTOR3(pv, 0, 1, 2);
5126  z1 = 1;
5127  }
5128  }
5129  } else {
5130  if (sB > 0) {
5131  if (sC < 0) { // (-+-).
5132  SETVECTOR3(U, C, A, B); // PT = ST
5133  SETVECTOR3(V, P, Q, R); // I2
5134  SETVECTOR3(pu, 2, 0, 1);
5135  SETVECTOR3(pv, 0, 1, 2);
5136  z1 = 0;
5137  } else {
5138  if (sC > 0) { // (-++).
5139  SETVECTOR3(U, B, C, A); // PT = ST x ST
5140  SETVECTOR3(V, Q, P, R); // PL = SL
5141  SETVECTOR3(pu, 1, 2, 0);
5142  SETVECTOR3(pv, 1, 0, 2);
5143  z1 = 0;
5144  } else { // (-+0).
5145  SETVECTOR3(U, C, A, B); // PT = ST
5146  SETVECTOR3(V, P, Q, R); // I2
5147  SETVECTOR3(pu, 2, 0, 1);
5148  SETVECTOR3(pv, 0, 1, 2);
5149  z1 = 2;
5150  }
5151  }
5152  } else {
5153  if (sC < 0) { // (-0-).
5154  SETVECTOR3(U, C, A, B); // PT = ST
5155  SETVECTOR3(V, P, Q, R); // I2
5156  SETVECTOR3(pu, 2, 0, 1);
5157  SETVECTOR3(pv, 0, 1, 2);
5158  z1 = 1;
5159  } else {
5160  if (sC > 0) { // (-0+).
5161  SETVECTOR3(U, B, C, A); // PT = ST x ST
5162  SETVECTOR3(V, Q, P, R); // PL = SL
5163  SETVECTOR3(pu, 1, 2, 0);
5164  SETVECTOR3(pv, 1, 0, 2);
5165  z1 = 2;
5166  } else { // (-00).
5167  SETVECTOR3(U, B, C, A); // PT = ST x ST
5168  SETVECTOR3(V, Q, P, R); // PL = SL
5169  SETVECTOR3(pu, 1, 2, 0);
5170  SETVECTOR3(pv, 1, 0, 2);
5171  z1 = 3;
5172  }
5173  }
5174  }
5175  }
5176  } else {
5177  if (sA > 0) {
5178  if (sB < 0) {
5179  if (sC < 0) { // (+--).
5180  SETVECTOR3(U, B, C, A); // PT = ST x ST
5181  SETVECTOR3(V, P, Q, R); // I2
5182  SETVECTOR3(pu, 1, 2, 0);
5183  SETVECTOR3(pv, 0, 1, 2);
5184  z1 = 0;
5185  } else {
5186  if (sC > 0) { // (+-+).
5187  SETVECTOR3(U, C, A, B); // PT = ST
5188  SETVECTOR3(V, Q, P, R); // PL = SL
5189  SETVECTOR3(pu, 2, 0, 1);
5190  SETVECTOR3(pv, 1, 0, 2);
5191  z1 = 0;
5192  } else { // (+-0).
5193  SETVECTOR3(U, C, A, B); // PT = ST
5194  SETVECTOR3(V, Q, P, R); // PL = SL
5195  SETVECTOR3(pu, 2, 0, 1);
5196  SETVECTOR3(pv, 1, 0, 2);
5197  z1 = 2;
5198  }
5199  }
5200  } else {
5201  if (sB > 0) {
5202  if (sC < 0) { // (++-).
5203  SETVECTOR3(U, A, B, C); // I3
5204  SETVECTOR3(V, Q, P, R); // PL = SL
5205  SETVECTOR3(pu, 0, 1, 2);
5206  SETVECTOR3(pv, 1, 0, 2);
5207  z1 = 0;
5208  } else {
5209  if (sC > 0) { // (+++).
5210  return 0;
5211  } else { // (++0).
5212  SETVECTOR3(U, A, B, C); // I3
5213  SETVECTOR3(V, Q, P, R); // PL = SL
5214  SETVECTOR3(pu, 0, 1, 2);
5215  SETVECTOR3(pv, 1, 0, 2);
5216  z1 = 1;
5217  }
5218  }
5219  } else { // (+0#)
5220  if (sC < 0) { // (+0-).
5221  SETVECTOR3(U, B, C, A); // PT = ST x ST
5222  SETVECTOR3(V, P, Q, R); // I2
5223  SETVECTOR3(pu, 1, 2, 0);
5224  SETVECTOR3(pv, 0, 1, 2);
5225  z1 = 2;
5226  } else {
5227  if (sC > 0) { // (+0+).
5228  SETVECTOR3(U, C, A, B); // PT = ST
5229  SETVECTOR3(V, Q, P, R); // PL = SL
5230  SETVECTOR3(pu, 2, 0, 1);
5231  SETVECTOR3(pv, 1, 0, 2);
5232  z1 = 1;
5233  } else { // (+00).
5234  SETVECTOR3(U, B, C, A); // PT = ST x ST
5235  SETVECTOR3(V, P, Q, R); // I2
5236  SETVECTOR3(pu, 1, 2, 0);
5237  SETVECTOR3(pv, 0, 1, 2);
5238  z1 = 3;
5239  }
5240  }
5241  }
5242  }
5243  } else {
5244  if (sB < 0) {
5245  if (sC < 0) { // (0--).
5246  SETVECTOR3(U, B, C, A); // PT = ST x ST
5247  SETVECTOR3(V, P, Q, R); // I2
5248  SETVECTOR3(pu, 1, 2, 0);
5249  SETVECTOR3(pv, 0, 1, 2);
5250  z1 = 1;
5251  } else {
5252  if (sC > 0) { // (0-+).
5253  SETVECTOR3(U, A, B, C); // I3
5254  SETVECTOR3(V, P, Q, R); // I2
5255  SETVECTOR3(pu, 0, 1, 2);
5256  SETVECTOR3(pv, 0, 1, 2);
5257  z1 = 2;
5258  } else { // (0-0).
5259  SETVECTOR3(U, C, A, B); // PT = ST
5260  SETVECTOR3(V, Q, P, R); // PL = SL
5261  SETVECTOR3(pu, 2, 0, 1);
5262  SETVECTOR3(pv, 1, 0, 2);
5263  z1 = 3;
5264  }
5265  }
5266  } else {
5267  if (sB > 0) {
5268  if (sC < 0) { // (0+-).
5269  SETVECTOR3(U, A, B, C); // I3
5270  SETVECTOR3(V, Q, P, R); // PL = SL
5271  SETVECTOR3(pu, 0, 1, 2);
5272  SETVECTOR3(pv, 1, 0, 2);
5273  z1 = 2;
5274  } else {
5275  if (sC > 0) { // (0++).
5276  SETVECTOR3(U, B, C, A); // PT = ST x ST
5277  SETVECTOR3(V, Q, P, R); // PL = SL
5278  SETVECTOR3(pu, 1, 2, 0);
5279  SETVECTOR3(pv, 1, 0, 2);
5280  z1 = 1;
5281  } else { // (0+0).
5282  SETVECTOR3(U, C, A, B); // PT = ST
5283  SETVECTOR3(V, P, Q, R); // I2
5284  SETVECTOR3(pu, 2, 0, 1);
5285  SETVECTOR3(pv, 0, 1, 2);
5286  z1 = 3;
5287  }
5288  }
5289  } else { // (00#)
5290  if (sC < 0) { // (00-).
5291  SETVECTOR3(U, A, B, C); // I3
5292  SETVECTOR3(V, Q, P, R); // PL = SL
5293  SETVECTOR3(pu, 0, 1, 2);
5294  SETVECTOR3(pv, 1, 0, 2);
5295  z1 = 3;
5296  } else {
5297  if (sC > 0) { // (00+).
5298  SETVECTOR3(U, A, B, C); // I3
5299  SETVECTOR3(V, P, Q, R); // I2
5300  SETVECTOR3(pu, 0, 1, 2);
5301  SETVECTOR3(pv, 0, 1, 2);
5302  z1 = 3;
5303  } else { // (000)
5304  // Not possible unless ABC is degenerate.
5305  // Avoiding compiler warnings.
5306  SETVECTOR3(U, A, B, C); // I3
5307  SETVECTOR3(V, P, Q, R); // I2
5308  SETVECTOR3(pu, 0, 1, 2);
5309  SETVECTOR3(pv, 0, 1, 2);
5310  z1 = 4;
5311  }
5312  }
5313  }
5314  }
5315  }
5316  }
5317 
5318  s1 = orient3d(U[0], U[2], R, V[1]); // A, C, R, Q
5319  s2 = orient3d(U[1], U[2], R, V[0]); // B, C, R, P
5320 
5321  if (s1 > 0) {
5322  return 0;
5323  }
5324  if (s2 < 0) {
5325  return 0;
5326  }
5327 
5328  if (level == 0) {
5329  return 1; // They are intersected.
5330  }
5331 
5332 
5333  if (z1 == 1) {
5334  if (s1 == 0) { // (0###)
5335  // C = Q.
5336  types[0] = (int) SHAREVERT;
5337  pos[0] = pu[2]; // C
5338  pos[1] = pv[1]; // Q
5339  types[1] = (int) DISJOINT;
5340  } else {
5341  if (s2 == 0) { // (#0##)
5342  // C = P.
5343  types[0] = (int) SHAREVERT;
5344  pos[0] = pu[2]; // C
5345  pos[1] = pv[0]; // P
5346  types[1] = (int) DISJOINT;
5347  } else { // (-+##)
5348  // C in [P, Q].
5349  types[0] = (int) ACROSSVERT;
5350  pos[0] = pu[2]; // C
5351  pos[1] = pv[0]; // [P, Q]
5352  types[1] = (int) DISJOINT;
5353  }
5354  }
5355  return 4;
5356  }
5357 
5358  s3 = orient3d(U[0], U[2], R, V[0]); // A, C, R, P
5359  s4 = orient3d(U[1], U[2], R, V[1]); // B, C, R, Q
5360 
5361  if (z1 == 0) { // (tritri-03)
5362  if (s1 < 0) {
5363  if (s3 > 0) {
5364  if (s4 > 0) {
5365  // [P, Q] overlaps [k, l] (-+++).
5366  types[0] = (int) ACROSSEDGE;
5367  pos[0] = pu[2]; // [C, A]
5368  pos[1] = pv[0]; // [P, Q]
5369  types[1] = (int) TOUCHFACE;
5370  pos[2] = 3; // [A, B, C]
5371  pos[3] = pv[1]; // Q
5372  } else {
5373  if (s4 == 0) {
5374  // Q = l, [P, Q] contains [k, l] (-++0).
5375  types[0] = (int) ACROSSEDGE;
5376  pos[0] = pu[2]; // [C, A]
5377  pos[1] = pv[0]; // [P, Q]
5378  types[1] = (int) TOUCHEDGE;
5379  pos[2] = pu[1]; // [B, C]
5380  pos[3] = pv[1]; // Q
5381  } else { // s4 < 0
5382  // [P, Q] contains [k, l] (-++-).
5383  types[0] = (int) ACROSSEDGE;
5384  pos[0] = pu[2]; // [C, A]
5385  pos[1] = pv[0]; // [P, Q]
5386  types[1] = (int) ACROSSEDGE;
5387  pos[2] = pu[1]; // [B, C]
5388  pos[3] = pv[0]; // [P, Q]
5389  }
5390  }
5391  } else {
5392  if (s3 == 0) {
5393  if (s4 > 0) {
5394  // P = k, [P, Q] in [k, l] (-+0+).
5395  types[0] = (int) TOUCHEDGE;
5396  pos[0] = pu[2]; // [C, A]
5397  pos[1] = pv[0]; // P
5398  types[1] = (int) TOUCHFACE;
5399  pos[2] = 3; // [A, B, C]
5400  pos[3] = pv[1]; // Q
5401  } else {
5402  if (s4 == 0) {
5403  // [P, Q] = [k, l] (-+00).
5404  types[0] = (int) TOUCHEDGE;
5405  pos[0] = pu[2]; // [C, A]
5406  pos[1] = pv[0]; // P
5407  types[1] = (int) TOUCHEDGE;
5408  pos[2] = pu[1]; // [B, C]
5409  pos[3] = pv[1]; // Q
5410  } else {
5411  // P = k, [P, Q] contains [k, l] (-+0-).
5412  types[0] = (int) TOUCHEDGE;
5413  pos[0] = pu[2]; // [C, A]
5414  pos[1] = pv[0]; // P
5415  types[1] = (int) ACROSSEDGE;
5416  pos[2] = pu[1]; // [B, C]
5417  pos[3] = pv[0]; // [P, Q]
5418  }
5419  }
5420  } else { // s3 < 0
5421  if (s2 > 0) {
5422  if (s4 > 0) {
5423  // [P, Q] in [k, l] (-+-+).
5424  types[0] = (int) TOUCHFACE;
5425  pos[0] = 3; // [A, B, C]
5426  pos[1] = pv[0]; // P
5427  types[1] = (int) TOUCHFACE;
5428  pos[2] = 3; // [A, B, C]
5429  pos[3] = pv[1]; // Q
5430  } else {
5431  if (s4 == 0) {
5432  // Q = l, [P, Q] in [k, l] (-+-0).
5433  types[0] = (int) TOUCHFACE;
5434  pos[0] = 3; // [A, B, C]
5435  pos[1] = pv[0]; // P
5436  types[1] = (int) TOUCHEDGE;
5437  pos[2] = pu[1]; // [B, C]
5438  pos[3] = pv[1]; // Q
5439  } else { // s4 < 0
5440  // [P, Q] overlaps [k, l] (-+--).
5441  types[0] = (int) TOUCHFACE;
5442  pos[0] = 3; // [A, B, C]
5443  pos[1] = pv[0]; // P
5444  types[1] = (int) ACROSSEDGE;
5445  pos[2] = pu[1]; // [B, C]
5446  pos[3] = pv[0]; // [P, Q]
5447  }
5448  }
5449  } else { // s2 == 0
5450  // P = l (#0##).
5451  types[0] = (int) TOUCHEDGE;
5452  pos[0] = pu[1]; // [B, C]
5453  pos[1] = pv[0]; // P
5454  types[1] = (int) DISJOINT;
5455  }
5456  }
5457  }
5458  } else { // s1 == 0
5459  // Q = k (0####)
5460  types[0] = (int) TOUCHEDGE;
5461  pos[0] = pu[2]; // [C, A]
5462  pos[1] = pv[1]; // Q
5463  types[1] = (int) DISJOINT;
5464  }
5465  } else if (z1 == 2) { // (tritri-23)
5466  if (s1 < 0) {
5467  if (s3 > 0) {
5468  if (s4 > 0) {
5469  // [P, Q] overlaps [A, l] (-+++).
5470  types[0] = (int) ACROSSVERT;
5471  pos[0] = pu[0]; // A
5472  pos[1] = pv[0]; // [P, Q]
5473  types[1] = (int) TOUCHFACE;
5474  pos[2] = 3; // [A, B, C]
5475  pos[3] = pv[1]; // Q
5476  } else {
5477  if (s4 == 0) {
5478  // Q = l, [P, Q] contains [A, l] (-++0).
5479  types[0] = (int) ACROSSVERT;
5480  pos[0] = pu[0]; // A
5481  pos[1] = pv[0]; // [P, Q]
5482  types[1] = (int) TOUCHEDGE;
5483  pos[2] = pu[1]; // [B, C]
5484  pos[3] = pv[1]; // Q
5485  } else { // s4 < 0
5486  // [P, Q] contains [A, l] (-++-).
5487  types[0] = (int) ACROSSVERT;
5488  pos[0] = pu[0]; // A
5489  pos[1] = pv[0]; // [P, Q]
5490  types[1] = (int) ACROSSEDGE;
5491  pos[2] = pu[1]; // [B, C]
5492  pos[3] = pv[0]; // [P, Q]
5493  }
5494  }
5495  } else {
5496  if (s3 == 0) {
5497  if (s4 > 0) {
5498  // P = A, [P, Q] in [A, l] (-+0+).
5499  types[0] = (int) SHAREVERT;
5500  pos[0] = pu[0]; // A
5501  pos[1] = pv[0]; // P
5502  types[1] = (int) TOUCHFACE;
5503  pos[2] = 3; // [A, B, C]
5504  pos[3] = pv[1]; // Q
5505  } else {
5506  if (s4 == 0) {
5507  // [P, Q] = [A, l] (-+00).
5508  types[0] = (int) SHAREVERT;
5509  pos[0] = pu[0]; // A
5510  pos[1] = pv[0]; // P
5511  types[1] = (int) TOUCHEDGE;
5512  pos[2] = pu[1]; // [B, C]
5513  pos[3] = pv[1]; // Q
5514  } else { // s4 < 0
5515  // Q = l, [P, Q] in [A, l] (-+0-).
5516  types[0] = (int) SHAREVERT;
5517  pos[0] = pu[0]; // A
5518  pos[1] = pv[0]; // P
5519  types[1] = (int) ACROSSEDGE;
5520  pos[2] = pu[1]; // [B, C]
5521  pos[3] = pv[0]; // [P, Q]
5522  }
5523  }
5524  } else { // s3 < 0
5525  if (s2 > 0) {
5526  if (s4 > 0) {
5527  // [P, Q] in [A, l] (-+-+).
5528  types[0] = (int) TOUCHFACE;
5529  pos[0] = 3; // [A, B, C]
5530  pos[1] = pv[0]; // P
5531  types[0] = (int) TOUCHFACE;
5532  pos[0] = 3; // [A, B, C]
5533  pos[1] = pv[1]; // Q
5534  } else {
5535  if (s4 == 0) {
5536  // Q = l, [P, Q] in [A, l] (-+-0).
5537  types[0] = (int) TOUCHFACE;
5538  pos[0] = 3; // [A, B, C]
5539  pos[1] = pv[0]; // P
5540  types[0] = (int) TOUCHEDGE;
5541  pos[0] = pu[1]; // [B, C]
5542  pos[1] = pv[1]; // Q
5543  } else { // s4 < 0
5544  // [P, Q] overlaps [A, l] (-+--).
5545  types[0] = (int) TOUCHFACE;
5546  pos[0] = 3; // [A, B, C]
5547  pos[1] = pv[0]; // P
5548  types[0] = (int) ACROSSEDGE;
5549  pos[0] = pu[1]; // [B, C]
5550  pos[1] = pv[0]; // [P, Q]
5551  }
5552  }
5553  } else { // s2 == 0
5554  // P = l (#0##).
5555  types[0] = (int) TOUCHEDGE;
5556  pos[0] = pu[1]; // [B, C]
5557  pos[1] = pv[0]; // P
5558  types[1] = (int) DISJOINT;
5559  }
5560  }
5561  }
5562  } else { // s1 == 0
5563  // Q = A (0###).
5564  types[0] = (int) SHAREVERT;
5565  pos[0] = pu[0]; // A
5566  pos[1] = pv[1]; // Q
5567  types[1] = (int) DISJOINT;
5568  }
5569  } else if (z1 == 3) { // (tritri-33)
5570  if (s1 < 0) {
5571  if (s3 > 0) {
5572  if (s4 > 0) {
5573  // [P, Q] overlaps [A, B] (-+++).
5574  types[0] = (int) ACROSSVERT;
5575  pos[0] = pu[0]; // A
5576  pos[1] = pv[0]; // [P, Q]
5577  types[1] = (int) TOUCHEDGE;
5578  pos[2] = pu[0]; // [A, B]
5579  pos[3] = pv[1]; // Q
5580  } else {
5581  if (s4 == 0) {
5582  // Q = B, [P, Q] contains [A, B] (-++0).
5583  types[0] = (int) ACROSSVERT;
5584  pos[0] = pu[0]; // A
5585  pos[1] = pv[0]; // [P, Q]
5586  types[1] = (int) SHAREVERT;
5587  pos[2] = pu[1]; // B
5588  pos[3] = pv[1]; // Q
5589  } else { // s4 < 0
5590  // [P, Q] contains [A, B] (-++-).
5591  types[0] = (int) ACROSSVERT;
5592  pos[0] = pu[0]; // A
5593  pos[1] = pv[0]; // [P, Q]
5594  types[1] = (int) ACROSSVERT;
5595  pos[2] = pu[1]; // B
5596  pos[3] = pv[0]; // [P, Q]
5597  }
5598  }
5599  } else {
5600  if (s3 == 0) {
5601  if (s4 > 0) {
5602  // P = A, [P, Q] in [A, B] (-+0+).
5603  types[0] = (int) SHAREVERT;
5604  pos[0] = pu[0]; // A
5605  pos[1] = pv[0]; // P
5606  types[1] = (int) TOUCHEDGE;
5607  pos[2] = pu[0]; // [A, B]
5608  pos[3] = pv[1]; // Q
5609  } else {
5610  if (s4 == 0) {
5611  // [P, Q] = [A, B] (-+00).
5612  types[0] = (int) SHAREEDGE;
5613  pos[0] = pu[0]; // [A, B]
5614  pos[1] = pv[0]; // [P, Q]
5615  types[1] = (int) DISJOINT;
5616  } else { // s4 < 0
5617  // P= A, [P, Q] in [A, B] (-+0-).
5618  types[0] = (int) SHAREVERT;
5619  pos[0] = pu[0]; // A
5620  pos[1] = pv[0]; // P
5621  types[1] = (int) ACROSSVERT;
5622  pos[2] = pu[1]; // B
5623  pos[3] = pv[0]; // [P, Q]
5624  }
5625  }
5626  } else { // s3 < 0
5627  if (s2 > 0) {
5628  if (s4 > 0) {
5629  // [P, Q] in [A, B] (-+-+).
5630  types[0] = (int) TOUCHEDGE;
5631  pos[0] = pu[0]; // [A, B]
5632  pos[1] = pv[0]; // P
5633  types[1] = (int) TOUCHEDGE;
5634  pos[2] = pu[0]; // [A, B]
5635  pos[3] = pv[1]; // Q
5636  } else {
5637  if (s4 == 0) {
5638  // Q = B, [P, Q] in [A, B] (-+-0).
5639  types[0] = (int) TOUCHEDGE;
5640  pos[0] = pu[0]; // [A, B]
5641  pos[1] = pv[0]; // P
5642  types[1] = (int) SHAREVERT;
5643  pos[2] = pu[1]; // B
5644  pos[3] = pv[1]; // Q
5645  } else { // s4 < 0
5646  // [P, Q] overlaps [A, B] (-+--).
5647  types[0] = (int) TOUCHEDGE;
5648  pos[0] = pu[0]; // [A, B]
5649  pos[1] = pv[0]; // P
5650  types[1] = (int) ACROSSVERT;
5651  pos[2] = pu[1]; // B
5652  pos[3] = pv[0]; // [P, Q]
5653  }
5654  }
5655  } else { // s2 == 0
5656  // P = B (#0##).
5657  types[0] = (int) SHAREVERT;
5658  pos[0] = pu[1]; // B
5659  pos[1] = pv[0]; // P
5660  types[1] = (int) DISJOINT;
5661  }
5662  }
5663  }
5664  } else { // s1 == 0
5665  // Q = A (0###).
5666  types[0] = (int) SHAREVERT;
5667  pos[0] = pu[0]; // A
5668  pos[1] = pv[1]; // Q
5669  types[1] = (int) DISJOINT;
5670  }
5671  }
5672 
5673  return 4;
5674 }
5675 
5676 int tetgenmesh::tri_edge_tail(point A,point B,point C,point P,point Q,point R,
5677  REAL sP,REAL sQ,int level,int *types,int *pos)
5678 {
5679  point U[3], V[3]; //, Ptmp;
5680  int pu[3], pv[3]; //, itmp;
5681  REAL s1, s2, s3;
5682  int z1;
5683 
5684 
5685  if (sP < 0) {
5686  if (sQ < 0) { // (--) disjoint
5687  return 0;
5688  } else {
5689  if (sQ > 0) { // (-+)
5690  SETVECTOR3(U, A, B, C);
5691  SETVECTOR3(V, P, Q, R);
5692  SETVECTOR3(pu, 0, 1, 2);
5693  SETVECTOR3(pv, 0, 1, 2);
5694  z1 = 0;
5695  } else { // (-0)
5696  SETVECTOR3(U, A, B, C);
5697  SETVECTOR3(V, P, Q, R);
5698  SETVECTOR3(pu, 0, 1, 2);
5699  SETVECTOR3(pv, 0, 1, 2);
5700  z1 = 1;
5701  }
5702  }
5703  } else {
5704  if (sP > 0) { // (+-)
5705  if (sQ < 0) {
5706  SETVECTOR3(U, A, B, C);
5707  SETVECTOR3(V, Q, P, R); // P and Q are flipped.
5708  SETVECTOR3(pu, 0, 1, 2);
5709  SETVECTOR3(pv, 1, 0, 2);
5710  z1 = 0;
5711  } else {
5712  if (sQ > 0) { // (++) disjoint
5713  return 0;
5714  } else { // (+0)
5715  SETVECTOR3(U, B, A, C); // A and B are flipped.
5716  SETVECTOR3(V, P, Q, R);
5717  SETVECTOR3(pu, 1, 0, 2);
5718  SETVECTOR3(pv, 0, 1, 2);
5719  z1 = 1;
5720  }
5721  }
5722  } else { // sP == 0
5723  if (sQ < 0) { // (0-)
5724  SETVECTOR3(U, A, B, C);
5725  SETVECTOR3(V, Q, P, R); // P and Q are flipped.
5726  SETVECTOR3(pu, 0, 1, 2);
5727  SETVECTOR3(pv, 1, 0, 2);
5728  z1 = 1;
5729  } else {
5730  if (sQ > 0) { // (0+)
5731  SETVECTOR3(U, B, A, C); // A and B are flipped.
5732  SETVECTOR3(V, Q, P, R); // P and Q are flipped.
5733  SETVECTOR3(pu, 1, 0, 2);
5734  SETVECTOR3(pv, 1, 0, 2);
5735  z1 = 1;
5736  } else { // (00)
5737  // A, B, C, P, and Q are coplanar.
5738  z1 = 2;
5739  }
5740  }
5741  }
5742  }
5743 
5744  if (z1 == 2) {
5745  // The triangle and the edge are coplanar.
5746  return tri_edge_2d(A, B, C, P, Q, R, level, types, pos);
5747  }
5748 
5749  s1 = orient3d(U[0], U[1], V[0], V[1]);
5750  if (s1 < 0) {
5751  return 0;
5752  }
5753 
5754  s2 = orient3d(U[1], U[2], V[0], V[1]);
5755  if (s2 < 0) {
5756  return 0;
5757  }
5758 
5759  s3 = orient3d(U[2], U[0], V[0], V[1]);
5760  if (s3 < 0) {
5761  return 0;
5762  }
5763 
5764  if (level == 0) {
5765  return 1; // The are intersected.
5766  }
5767 
5768  types[1] = (int) DISJOINT; // No second intersection point.
5769 
5770  if (z1 == 0) {
5771  if (s1 > 0) {
5772  if (s2 > 0) {
5773  if (s3 > 0) { // (+++)
5774  // [P, Q] passes interior of [A, B, C].
5775  types[0] = (int) ACROSSFACE;
5776  pos[0] = 3; // interior of [A, B, C]
5777  pos[1] = 0; // [P, Q]
5778  } else { // s3 == 0 (++0)
5779  // [P, Q] intersects [C, A].
5780  types[0] = (int) ACROSSEDGE;
5781  pos[0] = pu[2]; // [C, A]
5782  pos[1] = 0; // [P, Q]
5783  }
5784  } else { // s2 == 0
5785  if (s3 > 0) { // (+0+)
5786  // [P, Q] intersects [B, C].
5787  types[0] = (int) ACROSSEDGE;
5788  pos[0] = pu[1]; // [B, C]
5789  pos[1] = 0; // [P, Q]
5790  } else { // s3 == 0 (+00)
5791  // [P, Q] passes C.
5792  types[0] = (int) ACROSSVERT;
5793  pos[0] = pu[2]; // C
5794  pos[1] = 0; // [P, Q]
5795  }
5796  }
5797  } else { // s1 == 0
5798  if (s2 > 0) {
5799  if (s3 > 0) { // (0++)
5800  // [P, Q] intersects [A, B].
5801  types[0] = (int) ACROSSEDGE;
5802  pos[0] = pu[0]; // [A, B]
5803  pos[1] = 0; // [P, Q]
5804  } else { // s3 == 0 (0+0)
5805  // [P, Q] passes A.
5806  types[0] = (int) ACROSSVERT;
5807  pos[0] = pu[0]; // A
5808  pos[1] = 0; // [P, Q]
5809  }
5810  } else { // s2 == 0
5811  if (s3 > 0) { // (00+)
5812  // [P, Q] passes B.
5813  types[0] = (int) ACROSSVERT;
5814  pos[0] = pu[1]; // B
5815  pos[1] = 0; // [P, Q]
5816  }
5817  }
5818  }
5819  } else { // z1 == 1
5820  if (s1 > 0) {
5821  if (s2 > 0) {
5822  if (s3 > 0) { // (+++)
5823  // Q lies in [A, B, C].
5824  types[0] = (int) TOUCHFACE;
5825  pos[0] = 0; // [A, B, C]
5826  pos[1] = pv[1]; // Q
5827  } else { // s3 == 0 (++0)
5828  // Q lies on [C, A].
5829  types[0] = (int) TOUCHEDGE;
5830  pos[0] = pu[2]; // [C, A]
5831  pos[1] = pv[1]; // Q
5832  }
5833  } else { // s2 == 0
5834  if (s3 > 0) { // (+0+)
5835  // Q lies on [B, C].
5836  types[0] = (int) TOUCHEDGE;
5837  pos[0] = pu[1]; // [B, C]
5838  pos[1] = pv[1]; // Q
5839  } else { // s3 == 0 (+00)
5840  // Q = C.
5841  types[0] = (int) SHAREVERT;
5842  pos[0] = pu[2]; // C
5843  pos[1] = pv[1]; // Q
5844  }
5845  }
5846  } else { // s1 == 0
5847  if (s2 > 0) {
5848  if (s3 > 0) { // (0++)
5849  // Q lies on [A, B].
5850  types[0] = (int) TOUCHEDGE;
5851  pos[0] = pu[0]; // [A, B]
5852  pos[1] = pv[1]; // Q
5853  } else { // s3 == 0 (0+0)
5854  // Q = A.
5855  types[0] = (int) SHAREVERT;
5856  pos[0] = pu[0]; // A
5857  pos[1] = pv[1]; // Q
5858  }
5859  } else { // s2 == 0
5860  if (s3 > 0) { // (00+)
5861  // Q = B.
5862  types[0] = (int) SHAREVERT;
5863  pos[0] = pu[1]; // B
5864  pos[1] = pv[1]; // Q
5865  }
5866  }
5867  }
5868  }
5869 
5870  // T and E intersect in a single point.
5871  return 2;
5872 }
5873 
5874 int tetgenmesh::tri_edge_test(point A, point B, point C, point P, point Q,
5875  point R, int level, int *types, int *pos)
5876 {
5877  REAL sP, sQ;
5878 
5879  // Test the locations of P and Q with respect to ABC.
5880  sP = orient3d(A, B, C, P);
5881  sQ = orient3d(A, B, C, Q);
5882 
5883  return tri_edge_tail(A, B, C, P, Q, R, sP, sQ, level, types, pos);
5884 }
5885 
5887 // //
5888 // tri_tri_inter() Test whether two triangle (abc) and (opq) are //
5889 // intersecting or not. //
5890 // //
5891 // Return 0 if they are disjoint. Otherwise, return 1. 'type' returns one of //
5892 // the four cases: SHAREVERTEX, SHAREEDGE, SHAREFACE, and INTERSECT. //
5893 // //
5895 
5896 int tetgenmesh::tri_edge_inter_tail(REAL* A, REAL* B, REAL* C, REAL* P,
5897  REAL* Q, REAL s_p, REAL s_q)
5898 {
5899  int types[2], pos[4];
5900  int ni; // =0, 2, 4
5901 
5902  ni = tri_edge_tail(A, B, C, P, Q, NULL, s_p, s_q, 1, types, pos);
5903 
5904  if (ni > 0) {
5905  if (ni == 2) {
5906  // Get the intersection type.
5907  if (types[0] == (int) SHAREVERT) {
5908  return (int) SHAREVERT;
5909  } else {
5910  return (int) INTERSECT;
5911  }
5912  } else if (ni == 4) {
5913  // There may be two intersections.
5914  if (types[0] == (int) SHAREVERT) {
5915  if (types[1] == (int) DISJOINT) {
5916  return (int) SHAREVERT;
5917  } else {
5918  return (int) INTERSECT;
5919  }
5920  } else {
5921  if (types[0] == (int) SHAREEDGE) {
5922  return (int) SHAREEDGE;
5923  } else {
5924  return (int) INTERSECT;
5925  }
5926  }
5927  }
5928  }
5929 
5930  return (int) DISJOINT;
5931 }
5932 
5933 int tetgenmesh::tri_tri_inter(REAL* A,REAL* B,REAL* C,REAL* O,REAL* P,REAL* Q)
5934 {
5935  REAL s_o, s_p, s_q;
5936  REAL s_a, s_b, s_c;
5937 
5938  s_o = orient3d(A, B, C, O);
5939  s_p = orient3d(A, B, C, P);
5940  s_q = orient3d(A, B, C, Q);
5941  if ((s_o * s_p > 0.0) && (s_o * s_q > 0.0)) {
5942  // o, p, q are all in the same halfspace of ABC.
5943  return 0; // DISJOINT;
5944  }
5945 
5946  s_a = orient3d(O, P, Q, A);
5947  s_b = orient3d(O, P, Q, B);
5948  s_c = orient3d(O, P, Q, C);
5949  if ((s_a * s_b > 0.0) && (s_a * s_c > 0.0)) {
5950  // a, b, c are all in the same halfspace of OPQ.
5951  return 0; // DISJOINT;
5952  }
5953 
5954  int abcop, abcpq, abcqo;
5955  int shareedge = 0;
5956 
5957  abcop = tri_edge_inter_tail(A, B, C, O, P, s_o, s_p);
5958  if (abcop == (int) INTERSECT) {
5959  return (int) INTERSECT;
5960  } else if (abcop == (int) SHAREEDGE) {
5961  shareedge++;
5962  }
5963  abcpq = tri_edge_inter_tail(A, B, C, P, Q, s_p, s_q);
5964  if (abcpq == (int) INTERSECT) {
5965  return (int) INTERSECT;
5966  } else if (abcpq == (int) SHAREEDGE) {
5967  shareedge++;
5968  }
5969  abcqo = tri_edge_inter_tail(A, B, C, Q, O, s_q, s_o);
5970  if (abcqo == (int) INTERSECT) {
5971  return (int) INTERSECT;
5972  } else if (abcqo == (int) SHAREEDGE) {
5973  shareedge++;
5974  }
5975  if (shareedge == 3) {
5976  // opq are coincident with abc.
5977  return (int) SHAREFACE;
5978  }
5979 
5980  // Continue to detect whether opq and abc are intersecting or not.
5981  int opqab, opqbc, opqca;
5982 
5983  opqab = tri_edge_inter_tail(O, P, Q, A, B, s_a, s_b);
5984  if (opqab == (int) INTERSECT) {
5985  return (int) INTERSECT;
5986  }
5987  opqbc = tri_edge_inter_tail(O, P, Q, B, C, s_b, s_c);
5988  if (opqbc == (int) INTERSECT) {
5989  return (int) INTERSECT;
5990  }
5991  opqca = tri_edge_inter_tail(O, P, Q, C, A, s_c, s_a);
5992  if (opqca == (int) INTERSECT) {
5993  return (int) INTERSECT;
5994  }
5995 
5996  // At this point, two triangles are not intersecting and not coincident.
5997  // They may be share an edge, or share a vertex, or disjoint.
5998  if (abcop == (int) SHAREEDGE) {
5999  // op is coincident with an edge of abc.
6000  return (int) SHAREEDGE;
6001  }
6002  if (abcpq == (int) SHAREEDGE) {
6003  // pq is coincident with an edge of abc.
6004  return (int) SHAREEDGE;
6005  }
6006  if (abcqo == (int) SHAREEDGE) {
6007  // qo is coincident with an edge of abc.
6008  return (int) SHAREEDGE;
6009  }
6010 
6011  // They may share a vertex or disjoint.
6012  if (abcop == (int) SHAREVERT) {
6013  return (int) SHAREVERT;
6014  }
6015  if (abcpq == (int) SHAREVERT) {
6016  // q is the coincident vertex.
6017  return (int) SHAREVERT;
6018  }
6019 
6020  // They are disjoint.
6021  return (int) DISJOINT;
6022 }
6023 
6025 // //
6026 // lu_decmp() Compute the LU decomposition of a matrix. //
6027 // //
6028 // Compute the LU decomposition of a (non-singular) square matrix A using //
6029 // partial pivoting and implicit row exchanges. The result is: //
6030 // A = P * L * U, //
6031 // where P is a permutation matrix, L is unit lower triangular, and U is //
6032 // upper triangular. The factored form of A is used in combination with //
6033 // 'lu_solve()' to solve linear equations: Ax = b, or invert a matrix. //
6034 // //
6035 // The inputs are a square matrix 'lu[N..n+N-1][N..n+N-1]', it's size is 'n'.//
6036 // On output, 'lu' is replaced by the LU decomposition of a rowwise permuta- //
6037 // tion of itself, 'ps[N..n+N-1]' is an output vector that records the row //
6038 // permutation effected by the partial pivoting, effectively, 'ps' array //
6039 // tells the user what the permutation matrix P is; 'd' is output as +1/-1 //
6040 // depending on whether the number of row interchanges was even or odd, //
6041 // respectively. //
6042 // //
6043 // Return true if the LU decomposition is successfully computed, otherwise, //
6044 // return false in case that A is a singular matrix. //
6045 // //
6047 
6048 bool tetgenmesh::lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N)
6049 {
6050  REAL scales[4];
6051  REAL pivot, biggest, mult, tempf;
6052  int pivotindex = 0;
6053  int i, j, k;
6054 
6055  *d = 1.0; // No row interchanges yet.
6056 
6057  for (i = N; i < n + N; i++) { // For each row.
6058  // Find the largest element in each row for row equilibration
6059  biggest = 0.0;
6060  for (j = N; j < n + N; j++)
6061  if (biggest < (tempf = fabs(lu[i][j])))
6062  biggest = tempf;
6063  if (biggest != 0.0)
6064  scales[i] = 1.0 / biggest;
6065  else {
6066  scales[i] = 0.0;
6067  return false; // Zero row: singular matrix.
6068  }
6069  ps[i] = i; // Initialize pivot sequence.
6070  }
6071 
6072  for (k = N; k < n + N - 1; k++) { // For each column.
6073  // Find the largest element in each column to pivot around.
6074  biggest = 0.0;
6075  for (i = k; i < n + N; i++) {
6076  if (biggest < (tempf = fabs(lu[ps[i]][k]) * scales[ps[i]])) {
6077  biggest = tempf;
6078  pivotindex = i;
6079  }
6080  }
6081  if (biggest == 0.0) {
6082  return false; // Zero column: singular matrix.
6083  }
6084  if (pivotindex != k) { // Update pivot sequence.
6085  j = ps[k];
6086  ps[k] = ps[pivotindex];
6087  ps[pivotindex] = j;
6088  *d = -(*d); // ...and change the parity of d.
6089  }
6090 
6091  // Pivot, eliminating an extra variable each time
6092  pivot = lu[ps[k]][k];
6093  for (i = k + 1; i < n + N; i++) {
6094  lu[ps[i]][k] = mult = lu[ps[i]][k] / pivot;
6095  if (mult != 0.0) {
6096  for (j = k + 1; j < n + N; j++)
6097  lu[ps[i]][j] -= mult * lu[ps[k]][j];
6098  }
6099  }
6100  }
6101 
6102  // (lu[ps[n + N - 1]][n + N - 1] == 0.0) ==> A is singular.
6103  return lu[ps[n + N - 1]][n + N - 1] != 0.0;
6104 }
6105 
6107 // //
6108 // lu_solve() Solves the linear equation: Ax = b, after the matrix A //
6109 // has been decomposed into the lower and upper triangular //
6110 // matrices L and U, where A = LU. //
6111 // //
6112 // 'lu[N..n+N-1][N..n+N-1]' is input, not as the matrix 'A' but rather as //
6113 // its LU decomposition, computed by the routine 'lu_decmp'; 'ps[N..n+N-1]' //
6114 // is input as the permutation vector returned by 'lu_decmp'; 'b[N..n+N-1]' //
6115 // is input as the right-hand side vector, and returns with the solution //
6116 // vector. 'lu', 'n', and 'ps' are not modified by this routine and can be //
6117 // left in place for successive calls with different right-hand sides 'b'. //
6118 // //
6120 
6121 void tetgenmesh::lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N)
6122 {
6123  int i, j;
6124  REAL X[4], dot;
6125 
6126  for (i = N; i < n + N; i++) X[i] = 0.0;
6127 
6128  // Vector reduction using U triangular matrix.
6129  for (i = N; i < n + N; i++) {
6130  dot = 0.0;
6131  for (j = N; j < i + N; j++)
6132  dot += lu[ps[i]][j] * X[j];
6133  X[i] = b[ps[i]] - dot;
6134  }
6135 
6136  // Back substitution, in L triangular matrix.
6137  for (i = n + N - 1; i >= N; i--) {
6138  dot = 0.0;
6139  for (j = i + 1; j < n + N; j++)
6140  dot += lu[ps[i]][j] * X[j];
6141  X[i] = (X[i] - dot) / lu[ps[i]][i];
6142  }
6143 
6144  for (i = N; i < n + N; i++) b[i] = X[i];
6145 }
6146 
6148 // //
6149 // incircle3d() 3D in-circle test. //
6150 // //
6151 // Return a negative value if pd is inside the circumcircle of the triangle //
6152 // pa, pb, and pc. //
6153 // //
6154 // IMPORTANT: It assumes that [a,b] is the common edge, i.e., the two input //
6155 // triangles are [a,b,c] and [b,a,d]. //
6156 // //
6158 
6159 REAL tetgenmesh::incircle3d(point pa, point pb, point pc, point pd)
6160 {
6161  REAL area2[2], n1[3], n2[3], c[3];
6162  REAL sign, r, d;
6163 
6164  // Calculate the areas of the two triangles [a, b, c] and [b, a, d].
6165  facenormal(pa, pb, pc, n1, 1, NULL);
6166  area2[0] = dot(n1, n1);
6167  facenormal(pb, pa, pd, n2, 1, NULL);
6168  area2[1] = dot(n2, n2);
6169 
6170  if (area2[0] > area2[1]) {
6171  // Choose [a, b, c] as the base triangle.
6172  circumsphere(pa, pb, pc, NULL, c, &r);
6173  d = distance(c, pd);
6174  } else {
6175  // Choose [b, a, d] as the base triangle.
6176  if (area2[1] > 0) {
6177  circumsphere(pb, pa, pd, NULL, c, &r);
6178  d = distance(c, pc);
6179  } else {
6180  // The four points are collinear. This case only happens on the boundary.
6181  return 0; // Return "not inside".
6182  }
6183  }
6184 
6185  sign = d - r;
6186  if (fabs(sign) / r < b->epsilon) {
6187  sign = 0;
6188  }
6189 
6190  return sign;
6191 }
6192 
6194 // //
6195 // facenormal() Calculate the normal of the face. //
6196 // //
6197 // The normal of the face abc can be calculated by the cross product of 2 of //
6198 // its 3 edge vectors. A better choice of two edge vectors will reduce the //
6199 // numerical error during the calculation. Burdakov proved that the optimal //
6200 // basis problem is equivalent to the minimum spanning tree problem with the //
6201 // edge length be the functional, see Burdakov, "A greedy algorithm for the //
6202 // optimal basis problem", BIT 37:3 (1997), 591-599. If 'pivot' > 0, the two //
6203 // short edges in abc are chosen for the calculation. //
6204 // //
6205 // If 'lav' is not NULL and if 'pivot' is set, the average edge length of //
6206 // the edges of the face [a,b,c] is returned. //
6207 // //
6209 
6210 void tetgenmesh::facenormal(point pa, point pb, point pc, REAL *n, int pivot,
6211  REAL* lav)
6212 {
6213  REAL v1[3], v2[3], v3[3], *pv1, *pv2;
6214  REAL L1, L2, L3;
6215 
6216  v1[0] = pb[0] - pa[0]; // edge vector v1: a->b
6217  v1[1] = pb[1] - pa[1];
6218  v1[2] = pb[2] - pa[2];
6219  v2[0] = pa[0] - pc[0]; // edge vector v2: c->a
6220  v2[1] = pa[1] - pc[1];
6221  v2[2] = pa[2] - pc[2];
6222 
6223  // Default, normal is calculated by: v1 x (-v2) (see Fig. fnormal).
6224  if (pivot > 0) {
6225  // Choose edge vectors by Burdakov's algorithm.
6226  v3[0] = pc[0] - pb[0]; // edge vector v3: b->c
6227  v3[1] = pc[1] - pb[1];
6228  v3[2] = pc[2] - pb[2];
6229  L1 = dot(v1, v1);
6230  L2 = dot(v2, v2);
6231  L3 = dot(v3, v3);
6232  // Sort the three edge lengths.
6233  if (L1 < L2) {
6234  if (L2 < L3) {
6235  pv1 = v1; pv2 = v2; // n = v1 x (-v2).
6236  } else {
6237  pv1 = v3; pv2 = v1; // n = v3 x (-v1).
6238  }
6239  } else {
6240  if (L1 < L3) {
6241  pv1 = v1; pv2 = v2; // n = v1 x (-v2).
6242  } else {
6243  pv1 = v2; pv2 = v3; // n = v2 x (-v3).
6244  }
6245  }
6246  if (lav) {
6247  // return the average edge length.
6248  *lav = (sqrt(L1) + sqrt(L2) + sqrt(L3)) / 3.0;
6249  }
6250  } else {
6251  pv1 = v1; pv2 = v2; // n = v1 x (-v2).
6252  }
6253 
6254  // Calculate the face normal.
6255  cross(pv1, pv2, n);
6256  // Inverse the direction;
6257  n[0] = -n[0];
6258  n[1] = -n[1];
6259  n[2] = -n[2];
6260 }
6261 
6263 // //
6264 // shortdistance() Returns the shortest distance from point p to a line //
6265 // defined by two points e1 and e2. //
6266 // //
6267 // First compute the projection length l_p of the vector v1 = p - e1 along //
6268 // the vector v2 = e2 - e1. Then Pythagoras' Theorem is used to compute the //
6269 // shortest distance. //
6270 // //
6271 // This routine allows that p is collinear with the line. In this case, the //
6272 // return value is zero. The two points e1 and e2 should not be identical. //
6273 // //
6275 
6276 REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2)
6277 {
6278  REAL v1[3], v2[3];
6279  REAL len, l_p;
6280 
6281  v1[0] = e2[0] - e1[0];
6282  v1[1] = e2[1] - e1[1];
6283  v1[2] = e2[2] - e1[2];
6284  v2[0] = p[0] - e1[0];
6285  v2[1] = p[1] - e1[1];
6286  v2[2] = p[2] - e1[2];
6287 
6288  len = sqrt(dot(v1, v1));
6289 
6290  v1[0] /= len;
6291  v1[1] /= len;
6292  v1[2] /= len;
6293  l_p = dot(v1, v2);
6294 
6295  return sqrt(dot(v2, v2) - l_p * l_p);
6296 }
6297 
6299 // //
6300 // triarea() Return the area of a triangle. //
6301 // //
6303 
6304 REAL tetgenmesh::triarea(REAL* pa, REAL* pb, REAL* pc)
6305 {
6306  REAL A[4][4];
6307 
6308  // Compute the coefficient matrix A (3x3).
6309  A[0][0] = pb[0] - pa[0];
6310  A[0][1] = pb[1] - pa[1];
6311  A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
6312  A[1][0] = pc[0] - pa[0];
6313  A[1][1] = pc[1] - pa[1];
6314  A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
6315 
6316  cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
6317 
6318  return 0.5 * sqrt(dot(A[2], A[2])); // The area of [a,b,c].
6319 }
6320 
6321 REAL tetgenmesh::orient3dfast(REAL *pa, REAL *pb, REAL *pc, REAL *pd)
6322 {
6323  REAL adx, bdx, cdx;
6324  REAL ady, bdy, cdy;
6325  REAL adz, bdz, cdz;
6326 
6327  adx = pa[0] - pd[0];
6328  bdx = pb[0] - pd[0];
6329  cdx = pc[0] - pd[0];
6330  ady = pa[1] - pd[1];
6331  bdy = pb[1] - pd[1];
6332  cdy = pc[1] - pd[1];
6333  adz = pa[2] - pd[2];
6334  bdz = pb[2] - pd[2];
6335  cdz = pc[2] - pd[2];
6336 
6337  return adx * (bdy * cdz - bdz * cdy)
6338  + bdx * (cdy * adz - cdz * ady)
6339  + cdx * (ady * bdz - adz * bdy);
6340 }
6341 
6343 // //
6344 // interiorangle() Return the interior angle (0 - 2 * PI) between vectors //
6345 // o->p1 and o->p2. //
6346 // //
6347 // 'n' is the normal of the plane containing face (o, p1, p2). The interior //
6348 // angle is the total angle rotating from o->p1 around n to o->p2. Exchange //
6349 // the position of p1 and p2 will get the complement angle of the other one. //
6350 // i.e., interiorangle(o, p1, p2) = 2 * PI - interiorangle(o, p2, p1). Set //
6351 // 'n' be NULL if you only want the interior angle between 0 - PI. //
6352 // //
6354 
6355 REAL tetgenmesh::interiorangle(REAL* o, REAL* p1, REAL* p2, REAL* n)
6356 {
6357  REAL v1[3], v2[3], np[3];
6358  REAL theta, costheta, lenlen;
6359  REAL ori, len1, len2;
6360 
6361  // Get the interior angle (0 - PI) between o->p1, and o->p2.
6362  v1[0] = p1[0] - o[0];
6363  v1[1] = p1[1] - o[1];
6364  v1[2] = p1[2] - o[2];
6365  v2[0] = p2[0] - o[0];
6366  v2[1] = p2[1] - o[1];
6367  v2[2] = p2[2] - o[2];
6368  len1 = sqrt(dot(v1, v1));
6369  len2 = sqrt(dot(v2, v2));
6370  lenlen = len1 * len2;
6371 
6372  costheta = dot(v1, v2) / lenlen;
6373  if (costheta > 1.0) {
6374  costheta = 1.0; // Roundoff.
6375  } else if (costheta < -1.0) {
6376  costheta = -1.0; // Roundoff.
6377  }
6378  theta = acos(costheta);
6379  if (n != NULL) {
6380  // Get a point above the face (o, p1, p2);
6381  np[0] = o[0] + n[0];
6382  np[1] = o[1] + n[1];
6383  np[2] = o[2] + n[2];
6384  // Adjust theta (0 - 2 * PI).
6385  ori = orient3d(p1, o, np, p2);
6386  if (ori > 0.0) {
6387  theta = 2 * PI - theta;
6388  }
6389  }
6390 
6391  return theta;
6392 }
6393 
6395 // //
6396 // projpt2edge() Return the projection point from a point to an edge. //
6397 // //
6399 
6400 void tetgenmesh::projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj)
6401 {
6402  REAL v1[3], v2[3];
6403  REAL len, l_p;
6404 
6405  v1[0] = e2[0] - e1[0];
6406  v1[1] = e2[1] - e1[1];
6407  v1[2] = e2[2] - e1[2];
6408  v2[0] = p[0] - e1[0];
6409  v2[1] = p[1] - e1[1];
6410  v2[2] = p[2] - e1[2];
6411 
6412  len = sqrt(dot(v1, v1));
6413  v1[0] /= len;
6414  v1[1] /= len;
6415  v1[2] /= len;
6416  l_p = dot(v1, v2);
6417 
6418  prj[0] = e1[0] + l_p * v1[0];
6419  prj[1] = e1[1] + l_p * v1[1];
6420  prj[2] = e1[2] + l_p * v1[2];
6421 }
6422 
6424 // //
6425 // projpt2face() Return the projection point from a point to a face. //
6426 // //
6428 
6429 void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj)
6430 {
6431  REAL fnormal[3], v1[3];
6432  REAL len, dist;
6433 
6434  // Get the unit face normal.
6435  facenormal(f1, f2, f3, fnormal, 1, NULL);
6436  len = sqrt(fnormal[0]*fnormal[0] + fnormal[1]*fnormal[1] +
6437  fnormal[2]*fnormal[2]);
6438  fnormal[0] /= len;
6439  fnormal[1] /= len;
6440  fnormal[2] /= len;
6441  // Get the vector v1 = |p - f1|.
6442  v1[0] = p[0] - f1[0];
6443  v1[1] = p[1] - f1[1];
6444  v1[2] = p[2] - f1[2];
6445  // Get the project distance.
6446  dist = dot(fnormal, v1);
6447 
6448  // Get the project point.
6449  prj[0] = p[0] - dist * fnormal[0];
6450  prj[1] = p[1] - dist * fnormal[1];
6451  prj[2] = p[2] - dist * fnormal[2];
6452 }
6453 
6455 // //
6456 // tetalldihedral() Get all (six) dihedral angles of a tet. //
6457 // //
6458 // If 'cosdd' is not NULL, it returns the cosines of the 6 dihedral angles, //
6459 // the edge indices are given in the global array 'edge2ver'. If 'cosmaxd' //
6460 // (or 'cosmind') is not NULL, it returns the cosine of the maximal (or //
6461 // minimal) dihedral angle. //
6462 // //
6464 
6465 bool tetgenmesh::tetalldihedral(point pa, point pb, point pc, point pd,
6466  REAL* cosdd, REAL* cosmaxd, REAL* cosmind)
6467 {
6468  REAL N[4][3], vol, cosd, len;
6469  int f1 = 0, f2 = 0, i, j;
6470 
6471  vol = 0; // Check if the tet is valid or not.
6472 
6473  // Get four normals of faces of the tet.
6474  tetallnormal(pa, pb, pc, pd, N, &vol);
6475 
6476  if (vol > 0) {
6477  // Normalize the normals.
6478  for (i = 0; i < 4; i++) {
6479  len = sqrt(dot(N[i], N[i]));
6480  if (len != 0.0) {
6481  for (j = 0; j < 3; j++) N[i][j] /= len;
6482  } else {
6483  // There are degeneracies, such as duplicated vertices.
6484  vol = 0; //assert(0);
6485  }
6486  }
6487  }
6488 
6489  if (vol <= 0) { // if (vol == 0.0) {
6490  // A degenerated tet or an inverted tet.
6491  facenormal(pc, pb, pd, N[0], 1, NULL);
6492  facenormal(pa, pc, pd, N[1], 1, NULL);
6493  facenormal(pb, pa, pd, N[2], 1, NULL);
6494  facenormal(pa, pb, pc, N[3], 1, NULL);
6495  // Normalize the normals.
6496  for (i = 0; i < 4; i++) {
6497  len = sqrt(dot(N[i], N[i]));
6498  if (len != 0.0) {
6499  for (j = 0; j < 3; j++) N[i][j] /= len;
6500  } else {
6501  // There are degeneracies, such as duplicated vertices.
6502  break; // Not a valid normal.
6503  }
6504  }
6505  if (i < 4) {
6506  // Do not calculate dihedral angles.
6507  // Set all angles be 0 degree. There will be no quality optimization for
6508  // this tet! Use volume optimization to correct it.
6509  if (cosdd != NULL) {
6510  for (i = 0; i < 6; i++) {
6511  cosdd[i] = -1.0; // 180 degree.
6512  }
6513  }
6514  // This tet has zero volume.
6515  if (cosmaxd != NULL) {
6516  *cosmaxd = -1.0; // 180 degree.
6517  }
6518  if (cosmind != NULL) {
6519  *cosmind = -1.0; // 180 degree.
6520  }
6521  return false;
6522  }
6523  }
6524 
6525  // Calculate the cosine of the dihedral angles of the edges.
6526  for (i = 0; i < 6; i++) {
6527  switch (i) {
6528  case 0: f1 = 0; f2 = 1; break; // [c,d].
6529  case 1: f1 = 1; f2 = 2; break; // [a,d].
6530  case 2: f1 = 2; f2 = 3; break; // [a,b].
6531  case 3: f1 = 0; f2 = 3; break; // [b,c].
6532  case 4: f1 = 2; f2 = 0; break; // [b,d].
6533  case 5: f1 = 1; f2 = 3; break; // [a,c].
6534  }
6535  cosd = -dot(N[f1], N[f2]);
6536  if (cosd < -1.0) cosd = -1.0; // Rounding.
6537  if (cosd > 1.0) cosd = 1.0; // Rounding.
6538  if (cosdd) cosdd[i] = cosd;
6539  if (cosmaxd || cosmind) {
6540  if (i == 0) {
6541  if (cosmaxd) *cosmaxd = cosd;
6542  if (cosmind) *cosmind = cosd;
6543  } else {
6544  if (cosmaxd) *cosmaxd = cosd < *cosmaxd ? cosd : *cosmaxd;
6545  if (cosmind) *cosmind = cosd > *cosmind ? cosd : *cosmind;
6546  }
6547  }
6548  }
6549 
6550  return true;
6551 }
6552 
6554 // //
6555 // tetallnormal() Get the in-normals of the four faces of a given tet. //
6556 // //
6557 // Let tet be abcd. N[4][3] returns the four normals, which are: N[0] cbd, //
6558 // N[1] acd, N[2] bad, N[3] abc (exactly corresponding to the face indices //
6559 // of the mesh data structure). These normals are unnormalized. //
6560 // //
6562 
6563 void tetgenmesh::tetallnormal(point pa, point pb, point pc, point pd,
6564  REAL N[4][3], REAL* volume)
6565 {
6566  REAL A[4][4], rhs[4], D;
6567  int indx[4];
6568  int i, j;
6569 
6570  // get the entries of A[3][3].
6571  for (i = 0; i < 3; i++) A[0][i] = pa[i] - pd[i]; // d->a vec
6572  for (i = 0; i < 3; i++) A[1][i] = pb[i] - pd[i]; // d->b vec
6573  for (i = 0; i < 3; i++) A[2][i] = pc[i] - pd[i]; // d->c vec
6574 
6575  // Compute the inverse of matrix A, to get 3 normals of the 4 faces.
6576  if (lu_decmp(A, 3, indx, &D, 0)) { // Decompose the matrix just once.
6577  if (volume != NULL) {
6578  // Get the volume of the tet.
6579  *volume = fabs((A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2])) / 6.0;
6580  }
6581  for (j = 0; j < 3; j++) {
6582  for (i = 0; i < 3; i++) rhs[i] = 0.0;
6583  rhs[j] = 1.0; // Positive means the inside direction
6584  lu_solve(A, 3, indx, rhs, 0);
6585  for (i = 0; i < 3; i++) N[j][i] = rhs[i];
6586  }
6587  // Get the fourth normal by summing up the first three.
6588  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
6589  } else {
6590  // The tet is degenerated.
6591  if (volume != NULL) {
6592  *volume = 0;
6593  }
6594  }
6595 }
6596 
6598 // //
6599 // tetaspectratio() Calculate the aspect ratio of the tetrahedron. //
6600 // //
6601 // The aspect ratio of a tet is L/h, where L is the longest edge length, and //
6602 // h is the shortest height of the tet. //
6603 // //
6605 
6606 REAL tetgenmesh::tetaspectratio(point pa, point pb, point pc, point pd)
6607 {
6608  REAL V[6][3], edgelength[6], longlen;
6609  REAL vda[3], vdb[3], vdc[3];
6610  REAL N[4][3], A[4][4], rhs[4], D;
6611  REAL H[4], volume, minheightinv;
6612  int indx[4];
6613  int i, j;
6614 
6615  // Set the edge vectors: V[0], ..., V[5]
6616  for (i = 0; i < 3; i++) V[0][i] = pa[i] - pd[i];
6617  for (i = 0; i < 3; i++) V[1][i] = pb[i] - pd[i];
6618  for (i = 0; i < 3; i++) V[2][i] = pc[i] - pd[i];
6619  for (i = 0; i < 3; i++) V[3][i] = pb[i] - pa[i];
6620  for (i = 0; i < 3; i++) V[4][i] = pc[i] - pb[i];
6621  for (i = 0; i < 3; i++) V[5][i] = pa[i] - pc[i];
6622 
6623  // Get the squares of the edge lengths.
6624  for (i = 0; i < 6; i++) edgelength[i] = dot(V[i], V[i]);
6625 
6626  // Calculate the longest and shortest edge length.
6627  longlen = edgelength[0];
6628  for (i = 1; i < 6; i++) {
6629  longlen = edgelength[i] > longlen ? edgelength[i] : longlen;
6630  }
6631 
6632  // Set the matrix A = [vda, vdb, vdc]^T.
6633  for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
6634  for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
6635  for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
6636  // Lu-decompose the matrix A.
6637  lu_decmp(A, 3, indx, &D, 0);
6638  // Get the volume of abcd.
6639  volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
6640  // Check if it is zero.
6641  if (volume == 0.0) return 1.0e+200; // A degenerate tet.
6642 
6643  // Compute the 4 face normals (N[0], ..., N[3]).
6644  for (j = 0; j < 3; j++) {
6645  for (i = 0; i < 3; i++) rhs[i] = 0.0;
6646  rhs[j] = 1.0; // Positive means the inside direction
6647  lu_solve(A, 3, indx, rhs, 0);
6648  for (i = 0; i < 3; i++) N[j][i] = rhs[i];
6649  }
6650  // Get the fourth normal by summing up the first three.
6651  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
6652  // Normalized the normals.
6653  for (i = 0; i < 4; i++) {
6654  // H[i] is the inverse of the height of its corresponding face.
6655  H[i] = sqrt(dot(N[i], N[i]));
6656  // if (H[i] > 0.0) {
6657  // for (j = 0; j < 3; j++) N[i][j] /= H[i];
6658  // }
6659  }
6660  // Get the radius of the inscribed sphere.
6661  // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
6662  // Get the biggest H[i] (corresponding to the smallest height).
6663  minheightinv = H[0];
6664  for (i = 1; i < 4; i++) {
6665  if (H[i] > minheightinv) minheightinv = H[i];
6666  }
6667 
6668  return sqrt(longlen) * minheightinv;
6669 }
6670 
6672 // //
6673 // circumsphere() Calculate the smallest circumsphere (center and radius) //
6674 // of the given three or four points. //
6675 // //
6676 // The circumsphere of four points (a tetrahedron) is unique if they are not //
6677 // degenerate. If 'pd = NULL', the smallest circumsphere of three points is //
6678 // the diametral sphere of the triangle if they are not degenerate. //
6679 // //
6680 // Return TRUE if the input points are not degenerate and the circumcenter //
6681 // and circumradius are returned in 'cent' and 'radius' respectively if they //
6682 // are not NULLs. Otherwise, return FALSE, the four points are co-planar. //
6683 // //
6685 
6686 bool tetgenmesh::circumsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd,
6687  REAL* cent, REAL* radius)
6688 {
6689  REAL A[4][4], rhs[4], D;
6690  int indx[4];
6691 
6692  // Compute the coefficient matrix A (3x3).
6693  A[0][0] = pb[0] - pa[0];
6694  A[0][1] = pb[1] - pa[1];
6695  A[0][2] = pb[2] - pa[2];
6696  A[1][0] = pc[0] - pa[0];
6697  A[1][1] = pc[1] - pa[1];
6698  A[1][2] = pc[2] - pa[2];
6699  if (pd != NULL) {
6700  A[2][0] = pd[0] - pa[0];
6701  A[2][1] = pd[1] - pa[1];
6702  A[2][2] = pd[2] - pa[2];
6703  } else {
6704  cross(A[0], A[1], A[2]);
6705  }
6706 
6707  // Compute the right hand side vector b (3x1).
6708  rhs[0] = 0.5 * dot(A[0], A[0]);
6709  rhs[1] = 0.5 * dot(A[1], A[1]);
6710  if (pd != NULL) {
6711  rhs[2] = 0.5 * dot(A[2], A[2]);
6712  } else {
6713  rhs[2] = 0.0;
6714  }
6715 
6716  // Solve the 3 by 3 equations use LU decomposition with partial pivoting
6717  // and backward and forward substitute..
6718  if (!lu_decmp(A, 3, indx, &D, 0)) {
6719  if (radius != (REAL *) NULL) *radius = 0.0;
6720  return false;
6721  }
6722  lu_solve(A, 3, indx, rhs, 0);
6723  if (cent != (REAL *) NULL) {
6724  cent[0] = pa[0] + rhs[0];
6725  cent[1] = pa[1] + rhs[1];
6726  cent[2] = pa[2] + rhs[2];
6727  }
6728  if (radius != (REAL *) NULL) {
6729  *radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
6730  }
6731  return true;
6732 }
6733 
6735 // //
6736 // orthosphere() Calulcate the orthosphere of four weighted points. //
6737 // //
6738 // A weighted point (p, P^2) can be interpreted as a sphere centered at the //
6739 // point 'p' with a radius 'P'. The 'height' of 'p' is pheight = p[0]^2 + //
6740 // p[1]^2 + p[2]^2 - P^2. //
6741 // //
6743 
6744 bool tetgenmesh::orthosphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd,
6745  REAL aheight, REAL bheight, REAL cheight,
6746  REAL dheight, REAL* orthocent, REAL* radius)
6747 {
6748  REAL A[4][4], rhs[4], D;
6749  int indx[4];
6750 
6751  // Set the coefficient matrix A (4 x 4).
6752  A[0][0] = 1.0; A[0][1] = pa[0]; A[0][2] = pa[1]; A[0][3] = pa[2];
6753  A[1][0] = 1.0; A[1][1] = pb[0]; A[1][2] = pb[1]; A[1][3] = pb[2];
6754  A[2][0] = 1.0; A[2][1] = pc[0]; A[2][2] = pc[1]; A[2][3] = pc[2];
6755  A[3][0] = 1.0; A[3][1] = pd[0]; A[3][2] = pd[1]; A[3][3] = pd[2];
6756 
6757  // Set the right hand side vector (4 x 1).
6758  rhs[0] = 0.5 * aheight;
6759  rhs[1] = 0.5 * bheight;
6760  rhs[2] = 0.5 * cheight;
6761  rhs[3] = 0.5 * dheight;
6762 
6763  // Solve the 4 by 4 equations use LU decomposition with partial pivoting
6764  // and backward and forward substitute..
6765  if (!lu_decmp(A, 4, indx, &D, 0)) {
6766  if (radius != (REAL *) NULL) *radius = 0.0;
6767  return false;
6768  }
6769  lu_solve(A, 4, indx, rhs, 0);
6770 
6771  if (orthocent != (REAL *) NULL) {
6772  orthocent[0] = rhs[1];
6773  orthocent[1] = rhs[2];
6774  orthocent[2] = rhs[3];
6775  }
6776  if (radius != (REAL *) NULL) {
6777  // rhs[0] = - rheight / 2;
6778  // rheight = - 2 * rhs[0];
6779  // = r[0]^2 + r[1]^2 + r[2]^2 - radius^2
6780  // radius^2 = r[0]^2 + r[1]^2 + r[2]^2 -rheight
6781  // = r[0]^2 + r[1]^2 + r[2]^2 + 2 * rhs[0]
6782  *radius = sqrt(rhs[1] * rhs[1] + rhs[2] * rhs[2] + rhs[3] * rhs[3]
6783  + 2.0 * rhs[0]);
6784  }
6785  return true;
6786 }
6787 
6788 void tetgenmesh::tetcircumcenter(point tetorg, point tetdest, point tetfapex,
6789  point tettapex, REAL *circumcenter, REAL *radius)
6790 {
6791  REAL xot, yot, zot, xdt, ydt, zdt, xft, yft, zft;
6792  REAL otlength, dtlength, ftlength;
6793  REAL xcrossdf, ycrossdf, zcrossdf;
6794  REAL xcrossfo, ycrossfo, zcrossfo;
6795  REAL xcrossod, ycrossod, zcrossod;
6796  REAL denominator;
6797  REAL xct, yct, zct;
6798 
6799  //tetcircumcentercount++;
6800 
6801  /* Use coordinates relative to the apex of the tetrahedron. */
6802  xot = tetorg[0] - tettapex[0];
6803  yot = tetorg[1] - tettapex[1];
6804  zot = tetorg[2] - tettapex[2];
6805  xdt = tetdest[0] - tettapex[0];
6806  ydt = tetdest[1] - tettapex[1];
6807  zdt = tetdest[2] - tettapex[2];
6808  xft = tetfapex[0] - tettapex[0];
6809  yft = tetfapex[1] - tettapex[1];
6810  zft = tetfapex[2] - tettapex[2];
6811  /* Squares of lengths of the origin, destination, and face apex edges. */
6812  otlength = xot * xot + yot * yot + zot * zot;
6813  dtlength = xdt * xdt + ydt * ydt + zdt * zdt;
6814  ftlength = xft * xft + yft * yft + zft * zft;
6815  /* Cross products of the origin, destination, and face apex vectors. */
6816  xcrossdf = ydt * zft - yft * zdt;
6817  ycrossdf = zdt * xft - zft * xdt;
6818  zcrossdf = xdt * yft - xft * ydt;
6819  xcrossfo = yft * zot - yot * zft;
6820  ycrossfo = zft * xot - zot * xft;
6821  zcrossfo = xft * yot - xot * yft;
6822  xcrossod = yot * zdt - ydt * zot;
6823  ycrossod = zot * xdt - zdt * xot;
6824  zcrossod = xot * ydt - xdt * yot;
6825 
6826  /* Calculate the denominator of all the formulae. */
6827  //if (noexact) {
6828  // denominator = 0.5 / (xot * xcrossdf + yot * ycrossdf + zot * zcrossdf);
6829  //} else {
6830  /* Use the orient3d() routine to ensure a positive (and */
6831  /* reasonably accurate) result, avoiding any possibility */
6832  /* of division by zero. */
6833  denominator = 0.5 / orient3d(tetorg, tetdest, tetfapex, tettapex);
6834  /* Don't count the above as an orientation test. */
6835  //orientcount--;
6836  //}
6837 
6838  /* Calculate offset (from apex) of circumcenter. */
6839  xct = (otlength * xcrossdf + dtlength * xcrossfo + ftlength * xcrossod) *
6840  denominator;
6841  yct = (otlength * ycrossdf + dtlength * ycrossfo + ftlength * ycrossod) *
6842  denominator;
6843  zct = (otlength * zcrossdf + dtlength * zcrossfo + ftlength * zcrossod) *
6844  denominator;
6845 
6846  circumcenter[0] = xct + tettapex[0];
6847  circumcenter[1] = yct + tettapex[1];
6848  circumcenter[2] = zct + tettapex[2];
6849 
6850  if (radius != NULL) {
6851  *radius = sqrt(xct * xct + yct * yct + zct * zct);
6852  }
6853 }
6854 
6856 // //
6857 // planelineint() Calculate the intersection of a line and a plane. //
6858 // //
6859 // The equation of a plane (points P are on the plane with normal N and P3 //
6860 // on the plane) can be written as: N dot (P - P3) = 0. The equation of the //
6861 // line (points P on the line passing through P1 and P2) can be written as: //
6862 // P = P1 + u (P2 - P1). The intersection of these two occurs when: //
6863 // N dot (P1 + u (P2 - P1)) = N dot P3. //
6864 // Solving for u gives: //
6865 // N dot (P3 - P1) //
6866 // u = ------------------. //
6867 // N dot (P2 - P1) //
6868 // If the denominator is 0 then N (the normal to the plane) is perpendicular //
6869 // to the line. Thus the line is either parallel to the plane and there are //
6870 // no solutions or the line is on the plane in which case there are an infi- //
6871 // nite number of solutions. //
6872 // //
6873 // The plane is given by three points pa, pb, and pc, e1 and e2 defines the //
6874 // line. If u is non-zero, The intersection point (if exists) returns in ip. //
6875 // //
6877 
6878 void tetgenmesh::planelineint(REAL* pa, REAL* pb, REAL* pc, REAL* e1, REAL* e2,
6879  REAL* ip, REAL* u)
6880 {
6881  REAL n[3], det, det1;
6882 
6883  // Calculate N.
6884  facenormal(pa, pb, pc, n, 1, NULL);
6885  // Calculate N dot (e2 - e1).
6886  det = n[0] * (e2[0] - e1[0]) + n[1] * (e2[1] - e1[1])
6887  + n[2] * (e2[2] - e1[2]);
6888  if (det != 0.0) {
6889  // Calculate N dot (pa - e1)
6890  det1 = n[0] * (pa[0] - e1[0]) + n[1] * (pa[1] - e1[1])
6891  + n[2] * (pa[2] - e1[2]);
6892  *u = det1 / det;
6893  ip[0] = e1[0] + *u * (e2[0] - e1[0]);
6894  ip[1] = e1[1] + *u * (e2[1] - e1[1]);
6895  ip[2] = e1[2] + *u * (e2[2] - e1[2]);
6896  } else {
6897  *u = 0.0;
6898  }
6899 }
6900 
6902 // //
6903 // linelineint() Calculate the intersection(s) of two line segments. //
6904 // //
6905 // Calculate the line segment [P, Q] that is the shortest route between two //
6906 // lines from A to B and C to D. Calculate also the values of tp and tq //
6907 // where: P = A + tp (B - A), and Q = C + tq (D - C). //
6908 // //
6909 // Return 1 if the line segment exists. Otherwise, return 0. //
6910 // //
6912 
6913 int tetgenmesh::linelineint(REAL* A, REAL* B, REAL* C, REAL* D, REAL* P,
6914  REAL* Q, REAL* tp, REAL* tq)
6915 {
6916  REAL vab[3], vcd[3], vca[3];
6917  REAL vab_vab, vcd_vcd, vab_vcd;
6918  REAL vca_vab, vca_vcd;
6919  REAL det, eps;
6920  int i;
6921 
6922  for (i = 0; i < 3; i++) {
6923  vab[i] = B[i] - A[i];
6924  vcd[i] = D[i] - C[i];
6925  vca[i] = A[i] - C[i];
6926  }
6927 
6928  vab_vab = dot(vab, vab);
6929  vcd_vcd = dot(vcd, vcd);
6930  vab_vcd = dot(vab, vcd);
6931 
6932  det = vab_vab * vcd_vcd - vab_vcd * vab_vcd;
6933  // Round the result.
6934  eps = det / (fabs(vab_vab * vcd_vcd) + fabs(vab_vcd * vab_vcd));
6935  if (eps < b->epsilon) {
6936  return 0;
6937  }
6938 
6939  vca_vab = dot(vca, vab);
6940  vca_vcd = dot(vca, vcd);
6941 
6942  *tp = (vcd_vcd * (- vca_vab) + vab_vcd * vca_vcd) / det;
6943  *tq = (vab_vcd * (- vca_vab) + vab_vab * vca_vcd) / det;
6944 
6945  for (i = 0; i < 3; i++) P[i] = A[i] + (*tp) * vab[i];
6946  for (i = 0; i < 3; i++) Q[i] = C[i] + (*tq) * vcd[i];
6947 
6948  return 1;
6949 }
6950 
6952 // //
6953 // tetprismvol() Calculate the volume of a tetrahedral prism in 4D. //
6954 // //
6955 // A tetrahedral prism is a convex uniform polychoron (four dimensional poly-//
6956 // tope). It has 6 polyhedral cells: 2 tetrahedra connected by 4 triangular //
6957 // prisms. It has 14 faces: 8 triangular and 6 square. It has 16 edges and 8 //
6958 // vertices. (Wikipedia). //
6959 // //
6960 // Let 'p0', ..., 'p3' be four affinely independent points in R^3. They form //
6961 // the lower tetrahedral facet of the prism. The top tetrahedral facet is //
6962 // formed by four vertices, 'p4', ..., 'p7' in R^4, which is obtained by //
6963 // lifting each vertex of the lower facet into R^4 by a weight (height). A //
6964 // canonical choice of the weights is the square of Euclidean norm of of the //
6965 // points (vectors). //
6966 // //
6967 // //
6968 // The return value is (4!) 24 times of the volume of the tetrahedral prism. //
6969 // //
6971 
6972 REAL tetgenmesh::tetprismvol(REAL* p0, REAL* p1, REAL* p2, REAL* p3)
6973 {
6974  REAL *p4, *p5, *p6, *p7;
6975  REAL w4, w5, w6, w7;
6976  REAL vol[4];
6977 
6978  p4 = p0;
6979  p5 = p1;
6980  p6 = p2;
6981  p7 = p3;
6982 
6983  // TO DO: these weights can be pre-calculated!
6984  w4 = dot(p0, p0);
6985  w5 = dot(p1, p1);
6986  w6 = dot(p2, p2);
6987  w7 = dot(p3, p3);
6988 
6989  // Calculate the volume of the tet-prism.
6990  vol[0] = orient4d(p5, p6, p4, p3, p7, w5, w6, w4, 0, w7);
6991  vol[1] = orient4d(p3, p6, p2, p0, p1, 0, w6, 0, 0, 0);
6992  vol[2] = orient4d(p4, p6, p3, p0, p1, w4, w6, 0, 0, 0);
6993  vol[3] = orient4d(p6, p5, p4, p3, p1, w6, w5, w4, 0, 0);
6994 
6995  return fabs(vol[0]) + fabs(vol[1]) + fabs(vol[2]) + fabs(vol[3]);
6996 }
6997 
6999 // //
7000 // calculateabovepoint() Calculate a point above a facet in 'dummypoint'. //
7001 // //
7003 
7004 bool tetgenmesh::calculateabovepoint(arraypool *facpoints, point *ppa,
7005  point *ppb, point *ppc)
7006 {
7007  point *ppt, pa, pb, pc;
7008  REAL v1[3], v2[3], n[3];
7009  REAL lab, len, A, area;
7010  REAL x, y, z;
7011  int i;
7012 
7013  ppt = (point *) fastlookup(facpoints, 0);
7014  pa = *ppt; // a is the first point.
7015  pb = pc = NULL; // Avoid compiler warnings.
7016 
7017  // Get a point b s.t. the length of [a, b] is maximal.
7018  lab = 0;
7019  for (i = 1; i < facpoints->objects; i++) {
7020  ppt = (point *) fastlookup(facpoints, i);
7021  x = (*ppt)[0] - pa[0];
7022  y = (*ppt)[1] - pa[1];
7023  z = (*ppt)[2] - pa[2];
7024  len = x * x + y * y + z * z;
7025  if (len > lab) {
7026  lab = len;
7027  pb = *ppt;
7028  }
7029  }
7030  lab = sqrt(lab);
7031  if (lab == 0) {
7032  if (!b->quiet) {
7033  printf("Warning: All points of a facet are coincident with %d.\n",
7034  pointmark(pa));
7035  }
7036  return false;
7037  }
7038 
7039  // Get a point c s.t. the area of [a, b, c] is maximal.
7040  v1[0] = pb[0] - pa[0];
7041  v1[1] = pb[1] - pa[1];
7042  v1[2] = pb[2] - pa[2];
7043  A = 0;
7044  for (i = 1; i < facpoints->objects; i++) {
7045  ppt = (point *) fastlookup(facpoints, i);
7046  v2[0] = (*ppt)[0] - pa[0];
7047  v2[1] = (*ppt)[1] - pa[1];
7048  v2[2] = (*ppt)[2] - pa[2];
7049  cross(v1, v2, n);
7050  area = dot(n, n);
7051  if (area > A) {
7052  A = area;
7053  pc = *ppt;
7054  }
7055  }
7056  if (A == 0) {
7057  // All points are collinear. No above point.
7058  if (!b->quiet) {
7059  printf("Warning: All points of a facet are collinaer with [%d, %d].\n",
7060  pointmark(pa), pointmark(pb));
7061  }
7062  return false;
7063  }
7064 
7065  // Calculate an above point of this facet.
7066  facenormal(pa, pb, pc, n, 1, NULL);
7067  len = sqrt(dot(n, n));
7068  n[0] /= len;
7069  n[1] /= len;
7070  n[2] /= len;
7071  lab /= 2.0; // Half the maximal length.
7072  dummypoint[0] = pa[0] + lab * n[0];
7073  dummypoint[1] = pa[1] + lab * n[1];
7074  dummypoint[2] = pa[2] + lab * n[2];
7075 
7076  if (ppa != NULL) {
7077  // Return the three points.
7078  *ppa = pa;
7079  *ppb = pb;
7080  *ppc = pc;
7081  }
7082 
7083  return true;
7084 }
7085 
7087 // //
7088 // Calculate an above point. It lies above the plane containing the subface //
7089 // [a,b,c], and save it in dummypoint. Moreover, the vector pa->dummypoint //
7090 // is the normal of the plane. //
7091 // //
7093 
7094 void tetgenmesh::calculateabovepoint4(point pa, point pb, point pc, point pd)
7095 {
7096  REAL n1[3], n2[3], *norm;
7097  REAL len, len1, len2;
7098 
7099  // Select a base.
7100  facenormal(pa, pb, pc, n1, 1, NULL);
7101  len1 = sqrt(dot(n1, n1));
7102  facenormal(pa, pb, pd, n2, 1, NULL);
7103  len2 = sqrt(dot(n2, n2));
7104  if (len1 > len2) {
7105  norm = n1;
7106  len = len1;
7107  } else {
7108  norm = n2;
7109  len = len2;
7110  }
7111  norm[0] /= len;
7112  norm[1] /= len;
7113  norm[2] /= len;
7114  len = distance(pa, pb);
7115  dummypoint[0] = pa[0] + len * norm[0];
7116  dummypoint[1] = pa[1] + len * norm[1];
7117  dummypoint[2] = pa[2] + len * norm[2];
7118 }
7119 
7121 // //
7122 // report_overlapping_facets() Report two overlapping facets. //
7123 // //
7124 // Two subfaces, f1 [a, b, c] and f2 [a, b, d], share the same edge [a, b]. //
7125 // 'dihedang' is the dihedral angle between these two facets. It must less //
7126 // than the variable 'b->facet_overlap_angle_tol'. //
7127 // //
7129 
7130 void tetgenmesh::report_overlapping_facets(face *f1, face *f2, REAL dihedang)
7131 {
7132  point pa, pb, pc, pd;
7133 
7134  pa = sorg(*f1);
7135  pb = sdest(*f1);
7136  pc = sapex(*f1);
7137  pd = sapex(*f2);
7138 
7139  if (pc != pd) {
7140  printf("Found two %s self-intersecting facets.\n",
7141  dihedang > 0 ? "nearly" : "exactly");
7142  printf(" 1st: [%d, %d, %d] #%d\n",
7143  pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
7144  printf(" 2nd: [%d, %d, %d] #%d\n",
7145  pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
7146  if (dihedang > 0) {
7147  printf("The dihedral angle between them is %g degree.\n",
7148  dihedang / PI * 180.0);
7149  printf("Hint: You may use -p/# to decrease the dihedral angle");
7150  printf(" tolerance %g (degree).\n", b->facet_overlap_ang_tol);
7151  }
7152  } else {
7153  if (shellmark(*f1) != shellmark(*f2)) {
7154  // Two identical faces from two different facet.
7155  printf("Found two overlapping facets.\n");
7156  } else {
7157  printf("Found two duplicated facets.\n");
7158  }
7159  printf(" 1st: [%d, %d, %d] #%d\n",
7160  pointmark(pa), pointmark(pb), pointmark(pc), shellmark(*f1));
7161  printf(" 2nd: [%d, %d, %d] #%d\n",
7162  pointmark(pa), pointmark(pb), pointmark(pd), shellmark(*f2));
7163  }
7164 
7165  // Return the information
7166  sevent.e_type = 6;
7167  sevent.f_marker1 = shellmark(*f1);
7168  sevent.f_vertices1[0] = pointmark(pa);
7169  sevent.f_vertices1[1] = pointmark(pb);
7170  sevent.f_vertices1[2] = pointmark(pc);
7171  sevent.f_marker2 = shellmark(*f2);
7172  sevent.f_vertices2[0] = pointmark(pa);
7173  sevent.f_vertices2[1] = pointmark(pb);
7174  sevent.f_vertices2[2] = pointmark(pd);
7175 
7176  terminatetetgen(this, 3);
7177 }
7178 
7180 // //
7181 // report_selfint_edge() Report a self-intersection at an edge. //
7182 // //
7183 // The edge 'e1'->'e2' and the tetrahedron 'itet' intersect. 'dir' indicates //
7184 // that the edge intersects the tet at its origin vertex (ACROSSVERTEX), or //
7185 // its current face (ACROSSFACE), or its current edge (ACROSSEDGE). //
7186 // If 'iedge' is not NULL, it is either a segment or a subface that contains //
7187 // the edge 'e1'->'e2'. It is used to report the geometry entity. //
7188 // //
7189 // Since it is a self-intersection, the vertex, edge or face of 'itet' that //
7190 // is intersecting with this edge must be an input vertex, a segment, or a //
7191 // subface, respectively. //
7192 // //
7194 
7195 int tetgenmesh::report_selfint_edge(point e1, point e2, face *iedge,
7196  triface* itet, enum interresult dir)
7197 {
7198  point forg = NULL, fdest = NULL, fapex = NULL;
7199  int etype = 0, geomtag = 0, facemark = 0;
7200 
7201  if (iedge != NULL) {
7202  if (iedge->sh[5] != NULL) {
7203  etype = 2; // A subface
7204  forg = e1;
7205  fdest = e2;
7206  fapex = sapex(*iedge);
7207  facemark = shellmark(*iedge);
7208  } else {
7209  etype = 1; // A segment
7210  forg = farsorg(*iedge);
7211  fdest = farsdest(*iedge);
7212  // Get a facet containing this segment.
7213  face parentsh;
7214  spivot(*iedge, parentsh);
7215  if (parentsh.sh != NULL) {
7216  facemark = shellmark(parentsh);
7217  }
7218  }
7219  geomtag = shellmark(*iedge);
7220  }
7221 
7222  if (dir == SHAREEDGE) {
7223  // Two edges (segments) are coincide.
7224  face colseg;
7225  tsspivot1(*itet, colseg);
7226  if (etype == 1) {
7227  if (colseg.sh != iedge->sh) {
7228  face parentsh;
7229  spivot(colseg, parentsh);
7230  printf("PLC Error: Two segments are overlapping.\n");
7231  printf(" Segment 1: [%d, %d] #%d (%d)\n", pointmark(sorg(colseg)),
7232  pointmark(sdest(colseg)), shellmark(colseg),
7233  parentsh.sh ? shellmark(parentsh) : 0);
7234  printf(" Segment 2: [%d, %d] #%d (%d)\n", pointmark(forg),
7235  pointmark(fdest), geomtag, facemark);
7236  sevent.e_type = 4;
7237  sevent.f_marker1 = (parentsh.sh ? shellmark(parentsh) : 0);
7238  sevent.s_marker1 = shellmark(colseg);
7239  sevent.f_vertices1[0] = pointmark( sorg(colseg));
7240  sevent.f_vertices1[1] = pointmark(sdest(colseg));
7241  sevent.f_vertices1[2] = 0;
7242  sevent.f_marker2 = facemark;
7243  sevent.s_marker2 = geomtag;
7244  sevent.f_vertices2[0] = pointmark(forg);
7245  sevent.f_vertices2[1] = pointmark(fdest);
7246  sevent.f_vertices2[2] = 0;
7247  } else {
7248  // Two identical segments. Why report it?
7249  terminatetetgen(this, 2);
7250  }
7251  } else if (etype == 2) {
7252  printf("PLC Error: A segment lies in a facet.\n");
7253  printf(" Segment: [%d, %d] #%d\n", pointmark(sorg(colseg)),
7254  pointmark(sdest(colseg)), shellmark(colseg));
7255  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(forg),
7256  pointmark(fdest), pointmark(fapex), geomtag);
7257  sevent.e_type = 5;
7258  sevent.f_marker1 = 0;
7259  sevent.s_marker1 = shellmark(colseg);
7260  sevent.f_vertices1[0] = pointmark( sorg(colseg));
7261  sevent.f_vertices1[1] = pointmark(sdest(colseg));
7262  sevent.f_vertices1[2] = 0;
7263  sevent.f_marker2 = geomtag;
7264  sevent.s_marker2 = 0;
7265  sevent.f_vertices2[0] = pointmark(forg);
7266  sevent.f_vertices2[1] = pointmark(fdest);
7267  sevent.f_vertices2[2] = pointmark(fapex);
7268  }
7269  } else if (dir == SHAREFACE) {
7270  // Two triangles (subfaces) are coincide.
7271  face colface;
7272  tspivot(*itet, colface);
7273  if (etype == 2) {
7274  if (colface.sh != iedge->sh) {
7275  printf("PLC Error: Two facets are overlapping.\n");
7276  printf(" Facet 1: [%d,%d,%d] #%d\n", pointmark(forg),
7277  pointmark(fdest), pointmark(fapex), geomtag);
7278  printf(" Facet 2: [%d,%d,%d] #%d\n", pointmark(sorg(colface)),
7279  pointmark(sdest(colface)), pointmark(sapex(colface)),
7280  shellmark(colface));
7281  sevent.e_type = 6;
7282  sevent.f_marker1 = geomtag;
7283  sevent.s_marker1 = 0;
7284  sevent.f_vertices1[0] = pointmark(forg);
7285  sevent.f_vertices1[1] = pointmark(fdest);
7286  sevent.f_vertices1[2] = pointmark(fapex);
7287  sevent.f_marker2 = shellmark(colface);
7288  sevent.s_marker2 = 0;
7289  sevent.f_vertices2[0] = pointmark(sorg(colface));
7290  sevent.f_vertices2[1] = pointmark(sdest(colface));
7291  sevent.f_vertices2[2] = pointmark(sapex(colface));
7292  } else {
7293  // Two identical subfaces. Why report it?
7294  terminatetetgen(this, 2);
7295  }
7296  } else {
7297  terminatetetgen(this, 2);
7298  }
7299  } else if (dir == ACROSSVERT) {
7300  point pp = dest(*itet);
7301  if ((pointtype(pp) == RIDGEVERTEX) || (pointtype(pp) == FACETVERTEX)
7302  || (pointtype(pp) == VOLVERTEX)) {
7303  if (etype == 1) {
7304  printf("PLC Error: A vertex lies in a segment.\n");
7305  printf(" Vertex: [%d] (%g,%g,%g).\n",pointmark(pp),pp[0],pp[1],pp[2]);
7306  printf(" Segment: [%d, %d] #%d (%d)\n", pointmark(forg),
7307  pointmark(fdest), geomtag, facemark);
7308  sevent.e_type = 7;
7309  sevent.f_marker1 = 0;
7310  sevent.s_marker1 = 0;
7311  sevent.f_vertices1[0] = pointmark(pp);
7312  sevent.f_vertices1[1] = 0;
7313  sevent.f_vertices1[2] = 0;
7314  sevent.f_marker2 = facemark;
7315  sevent.s_marker2 = geomtag;
7316  sevent.f_vertices2[0] = pointmark(forg);
7317  sevent.f_vertices2[1] = pointmark(fdest);
7318  sevent.f_vertices2[2] = 0;
7319  sevent.int_point[0] = pp[0];
7320  sevent.int_point[1] = pp[1];
7321  sevent.int_point[2] = pp[2];
7322  } else if (etype == 2) {
7323  printf("PLC Error: A vertex lies in a facet.\n");
7324  printf(" Vertex: [%d] (%g,%g,%g).\n",pointmark(pp),pp[0],pp[1],pp[2]);
7325  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(forg), pointmark(fdest),
7326  pointmark(fapex), geomtag);
7327  sevent.e_type = 8;
7328  sevent.f_marker1 = 0;
7329  sevent.s_marker1 = 0;
7330  sevent.f_vertices1[0] = pointmark(pp);
7331  sevent.f_vertices1[1] = 0;
7332  sevent.f_vertices1[2] = 0;
7333  sevent.f_marker2 = geomtag;
7334  sevent.s_marker2 = 0;
7335  sevent.f_vertices2[0] = pointmark(forg);
7336  sevent.f_vertices2[1] = pointmark(fdest);
7337  sevent.f_vertices2[2] = pointmark(fapex);
7338  sevent.int_point[0] = pp[0];
7339  sevent.int_point[1] = pp[1];
7340  sevent.int_point[2] = pp[2];
7341  }
7342  } else if (pointtype(pp) == FREESEGVERTEX) {
7343  face parentseg, parentsh;
7344  sdecode(point2sh(pp), parentseg);
7345  spivot(parentseg, parentsh);
7346  if (parentseg.sh != NULL) {
7347  point p1 = farsorg(parentseg);
7348  point p2 = farsdest(parentseg);
7349  if (etype == 1) {
7350  printf("PLC Error: Two segments intersect at point (%g,%g,%g).\n",
7351  pp[0], pp[1], pp[2]);
7352  printf(" Segment 1: [%d, %d], #%d (%d)\n", pointmark(forg),
7353  pointmark(fdest), geomtag, facemark);
7354  printf(" Segment 2: [%d, %d], #%d (%d)\n", pointmark(p1),
7355  pointmark(p2), shellmark(parentseg),
7356  parentsh.sh ? shellmark(parentsh) : 0);
7357  sevent.e_type = 1;
7358  sevent.f_marker1 = facemark;
7359  sevent.s_marker1 = geomtag;
7360  sevent.f_vertices1[0] = pointmark(forg);
7361  sevent.f_vertices1[1] = pointmark(fdest);
7362  sevent.f_vertices1[2] = 0;
7363  sevent.f_marker2 = (parentsh.sh ? shellmark(parentsh) : 0);
7364  sevent.s_marker2 = shellmark(parentseg);
7365  sevent.f_vertices2[0] = pointmark(p1);
7366  sevent.f_vertices2[1] = pointmark(p2);
7367  sevent.f_vertices2[2] = 0;
7368  sevent.int_point[0] = pp[0];
7369  sevent.int_point[1] = pp[1];
7370  sevent.int_point[2] = pp[2];
7371  } else if (etype == 2) {
7372  printf("PLC Error: A segment and a facet intersect at point");
7373  printf(" (%g,%g,%g).\n", pp[0], pp[1], pp[2]);
7374  printf(" Segment: [%d, %d], #%d (%d)\n", pointmark(p1),
7375  pointmark(p2), shellmark(parentseg),
7376  parentsh.sh ? shellmark(parentsh) : 0);
7377  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(forg),
7378  pointmark(fdest), pointmark(fapex), geomtag);
7379  sevent.e_type = 2;
7380  sevent.f_marker1 = (parentsh.sh ? shellmark(parentsh) : 0);
7381  sevent.s_marker1 = shellmark(parentseg);
7382  sevent.f_vertices1[0] = pointmark(p1);
7383  sevent.f_vertices1[1] = pointmark(p2);
7384  sevent.f_vertices1[2] = 0;
7385  sevent.f_marker2 = geomtag;
7386  sevent.s_marker2 = 0;
7387  sevent.f_vertices2[0] = pointmark(forg);
7388  sevent.f_vertices2[1] = pointmark(fdest);
7389  sevent.f_vertices2[2] = pointmark(fapex);
7390  sevent.int_point[0] = pp[0];
7391  sevent.int_point[1] = pp[1];
7392  sevent.int_point[2] = pp[2];
7393  }
7394  } else {
7395  terminatetetgen(this, 2); // Report a bug.
7396  }
7397  } else if (pointtype(pp) == FREEFACETVERTEX) {
7398  face parentsh;
7399  sdecode(point2sh(pp), parentsh);
7400  if (parentsh.sh != NULL) {
7401  point p1 = sorg(parentsh);
7402  point p2 = sdest(parentsh);
7403  point p3 = sapex(parentsh);
7404  if (etype == 1) {
7405  printf("PLC Error: A segment and a facet intersect at point");
7406  printf(" (%g,%g,%g).\n", pp[0], pp[1], pp[2]);
7407  printf(" Segment : [%d, %d], #%d (%d)\n", pointmark(forg),
7408  pointmark(fdest), geomtag, facemark);
7409  printf(" Facet : [%d, %d, %d] #%d.\n", pointmark(p1),
7410  pointmark(p2), pointmark(p3), shellmark(parentsh));
7411  sevent.e_type = 2;
7412  sevent.f_marker1 = facemark;
7413  sevent.s_marker1 = geomtag;
7414  sevent.f_vertices1[0] = pointmark(forg);
7415  sevent.f_vertices1[1] = pointmark(fdest);
7416  sevent.f_vertices1[2] = 0;
7417  sevent.f_marker2 = shellmark(parentsh);
7418  sevent.s_marker2 = 0;
7419  sevent.f_vertices2[0] = pointmark(p1);
7420  sevent.f_vertices2[1] = pointmark(p2);
7421  sevent.f_vertices2[2] = pointmark(p3);
7422  sevent.int_point[0] = pp[0];
7423  sevent.int_point[1] = pp[1];
7424  sevent.int_point[2] = pp[2];
7425  } else if (etype == 2) {
7426  printf("PLC Error: Two facets intersect at point (%g,%g,%g).\n",
7427  pp[0], pp[1], pp[2]);
7428  printf(" Facet 1: [%d, %d, %d] #%d.\n", pointmark(forg),
7429  pointmark(fdest), pointmark(fapex), geomtag);
7430  printf(" Facet 2: [%d, %d, %d] #%d.\n", pointmark(p1),
7431  pointmark(p2), pointmark(p3), shellmark(parentsh));
7432  sevent.e_type = 3;
7433  sevent.f_marker1 = geomtag;
7434  sevent.s_marker1 = 0;
7435  sevent.f_vertices1[0] = pointmark(forg);
7436  sevent.f_vertices1[1] = pointmark(fdest);
7437  sevent.f_vertices1[2] = pointmark(fapex);
7438  sevent.f_marker2 = shellmark(parentsh);
7439  sevent.s_marker2 = 0;
7440  sevent.f_vertices2[0] = pointmark(p1);
7441  sevent.f_vertices2[1] = pointmark(p2);
7442  sevent.f_vertices2[2] = pointmark(p3);
7443  sevent.int_point[0] = pp[0];
7444  sevent.int_point[1] = pp[1];
7445  sevent.int_point[2] = pp[2];
7446  }
7447  } else {
7448  terminatetetgen(this, 2); // Report a bug.
7449  }
7450  } else if (pointtype(pp) == FREEVOLVERTEX) {
7451  // This is not a PLC error.
7452  // We should shift the vertex.
7453  // not down yet.
7454  terminatetetgen(this, 2); // Report a bug.
7455  } else {
7456  terminatetetgen(this, 2); // Report a bug.
7457  }
7458  terminatetetgen(this, 3);
7459  } else if (dir == ACROSSEDGE) {
7460  if (issubseg(*itet)) {
7461  face checkseg;
7462  tsspivot1(*itet, checkseg);
7463  face parentsh;
7464  spivot(checkseg, parentsh);
7465  // Calulcate the intersecting point.
7466  point p1 = sorg(checkseg);
7467  point p2 = sdest(checkseg);
7468  REAL P[3], Q[3], tp = 0, tq = 0;
7469  linelineint(e1, e2, p1, p2, P, Q, &tp, &tq);
7470  if (etype == 1) {
7471  printf("PLC Error: Two segments intersect at point (%g,%g,%g).\n",
7472  P[0], P[1], P[2]);
7473  printf(" Segment 1: [%d, %d] #%d (%d)\n", pointmark(forg),
7474  pointmark(fdest), geomtag, facemark);
7475  printf(" Segment 2: [%d, %d] #%d (%d)\n", pointmark(p1),
7476  pointmark(p2), shellmark(checkseg),
7477  parentsh.sh ? shellmark(parentsh) : 0);
7478  sevent.e_type = 1;
7479  sevent.f_marker1 = facemark;
7480  sevent.s_marker1 = geomtag;
7481  sevent.f_vertices1[0] = pointmark(forg);
7482  sevent.f_vertices1[1] = pointmark(fdest);
7483  sevent.f_vertices1[2] = 0;
7484  sevent.f_marker2 = (parentsh.sh ? shellmark(parentsh) : 0);
7485  sevent.s_marker2 = shellmark(checkseg);
7486  sevent.f_vertices2[0] = pointmark(p1);
7487  sevent.f_vertices2[1] = pointmark(p2);
7488  sevent.f_vertices2[2] = 0;
7489  sevent.int_point[0] = P[0];
7490  sevent.int_point[1] = P[1];
7491  sevent.int_point[2] = P[2];
7492  } else if (etype == 2) {
7493  printf("PLC Error: A segment and a facet intersect at point");
7494  printf(" (%g,%g,%g).\n", P[0], P[1], P[2]);
7495  printf(" Segment: [%d, %d] #%d (%d)\n", pointmark(p1),
7496  pointmark(p2), shellmark(checkseg),
7497  parentsh.sh ? shellmark(parentsh) : 0);
7498  printf(" Facet: [%d, %d, %d] #%d.\n", pointmark(forg),
7499  pointmark(fdest), pointmark(fapex), geomtag);
7500  sevent.e_type = 2;
7501  sevent.f_marker1 = (parentsh.sh ? shellmark(parentsh) : 0);
7502  sevent.s_marker1 = shellmark(checkseg);
7503  sevent.f_vertices1[0] = pointmark(p1);
7504  sevent.f_vertices1[1] = pointmark(p2);
7505  sevent.f_vertices1[2] = 0;
7506  sevent.f_marker2 = geomtag;
7507  sevent.s_marker2 = 0;
7508  sevent.f_vertices2[0] = pointmark(forg);
7509  sevent.f_vertices2[1] = pointmark(fdest);
7510  sevent.f_vertices2[2] = pointmark(fapex);
7511  sevent.int_point[0] = P[0];
7512  sevent.int_point[1] = P[1];
7513  sevent.int_point[2] = P[2];
7514  }
7515  terminatetetgen(this, 3);
7516  }
7517  } else if (dir == ACROSSFACE) {
7518  if (issubface(*itet)) {
7519  face checksh;
7520  tspivot(*itet, checksh);
7521  point p1 = sorg(checksh);
7522  point p2 = sdest(checksh);
7523  point p3 = sapex(checksh);
7524  REAL ip[3], u = 0;
7525  planelineint(p1, p2, p3, e1, e2, ip, &u);
7526  if (etype == 1) {
7527  printf("PLC Error: A segment and a facet intersect at point");
7528  printf(" (%g,%g,%g).\n", ip[0], ip[1], ip[2]);
7529  printf(" Segment: [%d, %d] #%d (%d)\n", pointmark(forg),
7530  pointmark(fdest), geomtag, facemark);
7531  printf(" Facet: [%d, %d, %d] #%d.\n", pointmark(p1),
7532  pointmark(p2), pointmark(p3), shellmark(checksh));
7533  sevent.e_type = 2;
7534  sevent.f_marker1 = facemark;
7535  sevent.s_marker1 = geomtag;
7536  sevent.f_vertices1[0] = pointmark(forg);
7537  sevent.f_vertices1[1] = pointmark(fdest);
7538  sevent.f_vertices1[2] = 0;
7539  sevent.f_marker2 = shellmark(checksh);
7540  sevent.s_marker2 = 0;
7541  sevent.f_vertices2[0] = pointmark(p1);
7542  sevent.f_vertices2[1] = pointmark(p2);
7543  sevent.f_vertices2[2] = pointmark(p3);
7544  sevent.int_point[0] = ip[0];
7545  sevent.int_point[1] = ip[1];
7546  sevent.int_point[2] = ip[2];
7547  } else if (etype == 2) {
7548  printf("PLC Error: Two facets intersect at point (%g,%g,%g).\n",
7549  ip[0], ip[1], ip[2]);
7550  printf(" Facet 1: [%d, %d, %d] #%d.\n", pointmark(forg),
7551  pointmark(fdest), pointmark(fapex), geomtag);
7552  printf(" Facet 2: [%d, %d, %d] #%d.\n", pointmark(p1),
7553  pointmark(p2), pointmark(p3), shellmark(checksh));
7554  sevent.e_type = 3;
7555  sevent.f_marker1 = geomtag;
7556  sevent.s_marker1 = 0;
7557  sevent.f_vertices1[0] = pointmark(forg);
7558  sevent.f_vertices1[1] = pointmark(fdest);
7559  sevent.f_vertices1[2] = pointmark(fapex);
7560  sevent.f_marker2 = shellmark(checksh);
7561  sevent.s_marker2 = 0;
7562  sevent.f_vertices2[0] = pointmark(p1);
7563  sevent.f_vertices2[1] = pointmark(p2);
7564  sevent.f_vertices2[2] = pointmark(p3);
7565  sevent.int_point[0] = ip[0];
7566  sevent.int_point[1] = ip[1];
7567  sevent.int_point[2] = ip[2];
7568  }
7569  terminatetetgen(this, 3);
7570  }
7571  } else {
7572  // An unknown 'dir'.
7573  terminatetetgen(this, 2);
7574  }
7575  return 0;
7576 }
7577 
7579 // //
7580 // report_selfint_face() Report a self-intersection at a facet. //
7581 // //
7582 // The triangle with vertices 'p1', 'p2', and 'p3' intersects with the edge //
7583 // of the tetrahedra 'iedge'. The intersection type is reported by 'intflag',//
7584 // 'types', and 'poss'. //
7585 // //
7586 // This routine ASSUMES (1) the triangle (p1,p2,p3) must belong to a facet, //
7587 // 'sface' is a subface of the same facet; and (2) 'iedge' must be either a //
7588 // segment or an edge of another facet. //
7589 // //
7591 
7592 int tetgenmesh::report_selfint_face(point p1, point p2, point p3, face* sface,
7593  triface* iedge, int intflag, int* types, int* poss)
7594 {
7595  face iface;
7596  point e1 = NULL, e2 = NULL, e3 = NULL;
7597  int etype = 0, geomtag = 0, facemark = 0;
7598 
7599  geomtag = shellmark(*sface);
7600 
7601  if (issubface(*iedge)) {
7602  tspivot(*iedge, iface);
7603  e1 = sorg(iface);
7604  e2 = sdest(iface);
7605  e3 = sapex(iface);
7606  etype = 2;
7607  facemark = geomtag;
7608  } else if (issubseg(*iedge)) {
7609  tsspivot1(*iedge, iface);
7610  e1 = farsorg(iface);
7611  e2 = farsdest(iface);
7612  etype = 1;
7613  face parentsh;
7614  spivot(iface, parentsh);
7615  facemark = shellmark(parentsh);
7616  } else {
7617  terminatetetgen(this, 2);
7618  }
7619 
7620  if (intflag == 2) {
7621  // The triangle and the edge intersect only at one point.
7622  REAL ip[3], u = 0;
7623  planelineint(p1, p2, p3, e1, e2, ip, &u);
7624  if ((types[0] == (int) ACROSSFACE) ||
7625  (types[0] == (int) ACROSSEDGE)) {
7626  // The triangle and the edge intersect in their interiors.
7627  if (etype == 1) {
7628  printf("PLC Error: A segment and a facet intersect at point");
7629  printf(" (%g,%g,%g).\n", ip[0], ip[1], ip[2]);
7630  printf(" Segment: [%d,%d] #%d (%d)\n", pointmark(e1), pointmark(e2),
7631  shellmark(iface), facemark);
7632  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(p1),
7633  pointmark(p2), pointmark(p3), geomtag);
7634  sevent.e_type = 2;
7635  sevent.f_marker1 = facemark;
7636  sevent.s_marker1 = shellmark(iface);
7637  sevent.f_vertices1[0] = pointmark(e1);
7638  sevent.f_vertices1[1] = pointmark(e2);
7639  sevent.f_vertices1[2] = 0;
7640  sevent.f_marker2 = geomtag;
7641  sevent.s_marker2 = 0;
7642  sevent.f_vertices2[0] = pointmark(p1);
7643  sevent.f_vertices2[1] = pointmark(p2);
7644  sevent.f_vertices2[2] = pointmark(p3);
7645  sevent.int_point[0] = ip[0];
7646  sevent.int_point[1] = ip[1];
7647  sevent.int_point[2] = ip[2];
7648  } else {
7649  printf("PLC Error: Two facets intersect at point");
7650  printf(" (%g,%g,%g).\n", ip[0], ip[1], ip[2]);
7651  printf(" Facet 1: [%d,%d,%d] #%d\n", pointmark(e1), pointmark(e2),
7652  pointmark(sorg(iface)), shellmark(iface));
7653  printf(" Facet 2: [%d,%d,%d] #%d\n", pointmark(p1),
7654  pointmark(p2), pointmark(p3), geomtag);
7655  sevent.e_type = 3;
7656  sevent.f_marker1 = shellmark(iface);
7657  sevent.s_marker1 = 0;
7658  sevent.f_vertices1[0] = pointmark(e1);
7659  sevent.f_vertices1[1] = pointmark(e2);
7660  sevent.f_vertices1[2] = pointmark(sorg(iface));
7661  sevent.f_marker2 = geomtag;
7662  sevent.s_marker2 = 0;
7663  sevent.f_vertices2[0] = pointmark(p1);
7664  sevent.f_vertices2[1] = pointmark(p2);
7665  sevent.f_vertices2[2] = pointmark(p3);
7666  sevent.int_point[0] = ip[0];
7667  sevent.int_point[1] = ip[1];
7668  sevent.int_point[2] = ip[2];
7669  }
7670  } else if (types[0] == (int) ACROSSVERT) {
7671  // A vertex of the triangle and the edge intersect.
7672  point crosspt = NULL;
7673  if (poss[0] == 0) {
7674  crosspt = p1;
7675  } else if (poss[0] == 1) {
7676  crosspt = p2;
7677  } else if (poss[0] == 2) {
7678  crosspt = p3;
7679  } else {
7680  terminatetetgen(this, 2);
7681  }
7682  if (!issteinerpoint(crosspt)) {
7683  if (etype == 1) {
7684  printf("PLC Error: A vertex and a segment intersect at (%g,%g,%g)\n",
7685  crosspt[0], crosspt[1], crosspt[2]);
7686  printf(" Vertex: #%d\n", pointmark(crosspt));
7687  printf(" Segment: [%d,%d] #%d (%d)\n", pointmark(e1), pointmark(e2),
7688  shellmark(iface), facemark);
7689  sevent.e_type = 7;
7690  sevent.f_marker1 = 0;
7691  sevent.s_marker1 = 0;
7692  sevent.f_vertices1[0] = pointmark(crosspt);
7693  sevent.f_vertices1[1] = 0;
7694  sevent.f_vertices1[2] = 0;
7695  sevent.f_marker2 = facemark;
7696  sevent.s_marker2 = shellmark(iface);
7697  sevent.f_vertices2[0] = pointmark(e1);
7698  sevent.f_vertices2[1] = pointmark(e2);
7699  sevent.f_vertices2[2] = 0;
7700  sevent.int_point[0] = crosspt[0];
7701  sevent.int_point[1] = crosspt[1];
7702  sevent.int_point[2] = crosspt[2];
7703  } else {
7704  printf("PLC Error: A vertex and a facet intersect at (%g,%g,%g)\n",
7705  crosspt[0], crosspt[1], crosspt[2]);
7706  printf(" Vertex: #%d\n", pointmark(crosspt));
7707  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(p1),
7708  pointmark(p2), pointmark(p3), geomtag);
7709  sevent.e_type = 8;
7710  sevent.f_marker1 = 0;
7711  sevent.s_marker1 = 0;
7712  sevent.f_vertices1[0] = pointmark(crosspt);
7713  sevent.f_vertices1[1] = 0;
7714  sevent.f_vertices1[2] = 0;
7715  sevent.f_marker2 = geomtag;
7716  sevent.s_marker2 = 0;
7717  sevent.f_vertices2[0] = pointmark(p1);
7718  sevent.f_vertices2[1] = pointmark(p2);
7719  sevent.f_vertices2[2] = pointmark(p3);
7720  sevent.int_point[0] = crosspt[0];
7721  sevent.int_point[1] = crosspt[1];
7722  sevent.int_point[2] = crosspt[2];
7723  }
7724  } else {
7725  // It is a Steiner point. To be processed.
7726  terminatetetgen(this, 2);
7727  }
7728  } else if ((types[0] == (int) TOUCHFACE) ||
7729  (types[0] == (int) TOUCHEDGE)) {
7730  // The triangle and a vertex of the edge intersect.
7731  point touchpt = NULL;
7732  if (poss[1] == 0) {
7733  touchpt = org(*iedge);
7734  } else if (poss[1] == 1) {
7735  touchpt = dest(*iedge);
7736  } else {
7737  terminatetetgen(this, 2);
7738  }
7739  if (!issteinerpoint(touchpt)) {
7740  printf("PLC Error: A vertex and a facet intersect at (%g,%g,%g)\n",
7741  touchpt[0], touchpt[1], touchpt[2]);
7742  printf(" Vertex: #%d\n", pointmark(touchpt));
7743  printf(" Facet: [%d,%d,%d] #%d\n", pointmark(p1),
7744  pointmark(p2), pointmark(p3), geomtag);
7745  sevent.e_type = 8;
7746  sevent.f_marker1 = 0;
7747  sevent.s_marker1 = 0;
7748  sevent.f_vertices1[0] = pointmark(touchpt);
7749  sevent.f_vertices1[1] = 0;
7750  sevent.f_vertices1[2] = 0;
7751  sevent.f_marker2 = geomtag;
7752  sevent.s_marker2 = 0;
7753  sevent.f_vertices2[0] = pointmark(p1);
7754  sevent.f_vertices2[1] = pointmark(p2);
7755  sevent.f_vertices2[2] = pointmark(p3);
7756  sevent.int_point[0] = touchpt[0];
7757  sevent.int_point[1] = touchpt[1];
7758  sevent.int_point[2] = touchpt[2];
7759  } else {
7760  // It is a Steiner point. To be processed.
7761  terminatetetgen(this, 2);
7762  }
7763  } else if (types[0] == (int) SHAREVERT) {
7764  terminatetetgen(this, 2);
7765  } else {
7766  terminatetetgen(this, 2);
7767  }
7768  } else if (intflag == 4) {
7769  if (types[0] == (int) SHAREFACE) {
7770  printf("PLC Error: Two facets are overlapping.\n");
7771  printf(" Facet 1: [%d,%d,%d] #%d\n", pointmark(e1),
7772  pointmark(e2), pointmark(e3), facemark);
7773  printf(" Facet 2: [%d,%d,%d] #%d\n", pointmark(p1),
7774  pointmark(p2), pointmark(p3), geomtag);
7775  sevent.e_type = 6;
7776  sevent.f_marker1 = facemark;
7777  sevent.s_marker1 = 0;
7778  sevent.f_vertices1[0] = pointmark(e1);
7779  sevent.f_vertices1[1] = pointmark(e2);
7780  sevent.f_vertices1[2] = pointmark(e3);
7781  sevent.f_marker2 = geomtag;
7782  sevent.s_marker2 = 0;
7783  sevent.f_vertices2[0] = pointmark(p1);
7784  sevent.f_vertices2[1] = pointmark(p2);
7785  sevent.f_vertices2[2] = pointmark(p3);
7786  } else {
7787  terminatetetgen(this, 2);
7788  }
7789  } else {
7790  terminatetetgen(this, 2);
7791  }
7792 
7793  terminatetetgen(this, 3);
7794  return 0;
7795 }
7796 
7800 
7804 
7806 // //
7807 // flip23() Perform a 2-to-3 flip (face-to-edge flip). //
7808 // //
7809 // 'fliptets' is an array of three tets (handles), where the [0] and [1] are //
7810 // [a,b,c,d] and [b,a,c,e]. The three new tets: [e,d,a,b], [e,d,b,c], and //
7811 // [e,d,c,a] are returned in [0], [1], and [2] of 'fliptets'. As a result, //
7812 // The face [a,b,c] is removed, and the edge [d,e] is created. //
7813 // //
7814 // If 'hullflag' > 0, hull tets may be involved in this flip, i.e., one of //
7815 // the five vertices may be 'dummypoint'. There are two canonical cases: //
7816 // (1) d is 'dummypoint', then all three new tets are hull tets. If e is //
7817 // 'dummypoint', we reconfigure e to d, i.e., turn it up-side down. //
7818 // (2) c is 'dummypoint', then two new tets: [e,d,b,c] and [e,d,c,a], are //
7819 // hull tets. If a or b is 'dummypoint', we reconfigure it to c, i.e., //
7820 // rotate the three input tets counterclockwisely (right-hand rule) //
7821 // until a or b is in c's position. //
7822 // //
7823 // If 'fc->enqflag' is set, convex hull faces will be queued for flipping. //
7824 // In particular, if 'fc->enqflag' is 1, it is called by incrementalflip() //
7825 // after the insertion of a new point. It is assumed that 'd' is the new //
7826 // point. IN this case, only link faces of 'd' are queued. //
7827 // //
7829 
7830 void tetgenmesh::flip23(triface* fliptets, int hullflag, flipconstraints *fc)
7831 {
7832  triface topcastets[3], botcastets[3];
7833  triface newface, casface;
7834  point pa, pb, pc, pd, pe;
7835  REAL attrib, volume;
7836  int dummyflag = 0; // range = {-1, 0, 1, 2}.
7837  int i;
7838 
7839  if (hullflag > 0) {
7840  // Check if e is dummypoint.
7841  if (oppo(fliptets[1]) == dummypoint) {
7842  // Swap the two old tets.
7843  newface = fliptets[0];
7844  fliptets[0] = fliptets[1];
7845  fliptets[1] = newface;
7846  dummyflag = -1; // d is dummypoint.
7847  } else {
7848  // Check if either a or b is dummypoint.
7849  if (org(fliptets[0]) == dummypoint) {
7850  dummyflag = 1; // a is dummypoint.
7851  enextself(fliptets[0]);
7852  eprevself(fliptets[1]);
7853  } else if (dest(fliptets[0]) == dummypoint) {
7854  dummyflag = 2; // b is dummypoint.
7855  eprevself(fliptets[0]);
7856  enextself(fliptets[1]);
7857  } else {
7858  dummyflag = 0; // either c or d may be dummypoint.
7859  }
7860  }
7861  }
7862 
7863  pa = org(fliptets[0]);
7864  pb = dest(fliptets[0]);
7865  pc = apex(fliptets[0]);
7866  pd = oppo(fliptets[0]);
7867  pe = oppo(fliptets[1]);
7868 
7869  flip23count++;
7870 
7871  // Get the outer boundary faces.
7872  for (i = 0; i < 3; i++) {
7873  fnext(fliptets[0], topcastets[i]);
7874  enextself(fliptets[0]);
7875  }
7876  for (i = 0; i < 3; i++) {
7877  fnext(fliptets[1], botcastets[i]);
7878  eprevself(fliptets[1]);
7879  }
7880 
7881  // Re-use fliptets[0] and fliptets[1].
7882  fliptets[0].ver = 11;
7883  fliptets[1].ver = 11;
7884  setelemmarker(fliptets[0].tet, 0); // Clear all flags.
7885  setelemmarker(fliptets[1].tet, 0);
7886  // NOTE: the element attributes and volume constraint remain unchanged.
7887  if (checksubsegflag) {
7888  // Dealloc the space to subsegments.
7889  if (fliptets[0].tet[8] != NULL) {
7890  tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
7891  fliptets[0].tet[8] = NULL;
7892  }
7893  if (fliptets[1].tet[8] != NULL) {
7894  tet2segpool->dealloc((shellface *) fliptets[1].tet[8]);
7895  fliptets[1].tet[8] = NULL;
7896  }
7897  }
7898  if (checksubfaceflag) {
7899  // Dealloc the space to subfaces.
7900  if (fliptets[0].tet[9] != NULL) {
7901  tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
7902  fliptets[0].tet[9] = NULL;
7903  }
7904  if (fliptets[1].tet[9] != NULL) {
7905  tet2subpool->dealloc((shellface *) fliptets[1].tet[9]);
7906  fliptets[1].tet[9] = NULL;
7907  }
7908  }
7909  // Create a new tet.
7910  maketetrahedron(&(fliptets[2]));
7911  // The new tet have the same attributes from the old tet.
7912  for (i = 0; i < numelemattrib; i++) {
7913  attrib = elemattribute(fliptets[0].tet, i);
7914  setelemattribute(fliptets[2].tet, i, attrib);
7915  }
7916  if (b->varvolume) {
7917  volume = volumebound(fliptets[0].tet);
7918  setvolumebound(fliptets[2].tet, volume);
7919  }
7920 
7921  if (hullflag > 0) {
7922  // Check if d is dummytet.
7923  if (pd != dummypoint) {
7924  setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] *
7925  setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] *
7926  // Check if c is dummypoint.
7927  if (pc != dummypoint) {
7928  setvertices(fliptets[2], pe, pd, pc, pa); // [e,d,c,a] *
7929  } else {
7930  setvertices(fliptets[2], pd, pe, pa, pc); // [d,e,a,c]
7931  esymself(fliptets[2]); // [e,d,c,a] *
7932  }
7933  // The hullsize does not change.
7934  } else {
7935  // d is dummypoint.
7936  setvertices(fliptets[0], pa, pb, pe, pd); // [a,b,e,d]
7937  setvertices(fliptets[1], pb, pc, pe, pd); // [b,c,e,d]
7938  setvertices(fliptets[2], pc, pa, pe, pd); // [c,a,e,d]
7939  // Adjust the faces to [e,d,a,b], [e,d,b,c], [e,d,c,a] *
7940  for (i = 0; i < 3; i++) {
7941  eprevesymself(fliptets[i]);
7942  enextself(fliptets[i]);
7943  }
7944  // We deleted one hull tet, and created three hull tets.
7945  hullsize += 2;
7946  }
7947  } else {
7948  setvertices(fliptets[0], pe, pd, pa, pb); // [e,d,a,b] *
7949  setvertices(fliptets[1], pe, pd, pb, pc); // [e,d,b,c] *
7950  setvertices(fliptets[2], pe, pd, pc, pa); // [e,d,c,a] *
7951  }
7952 
7953  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
7954  REAL volneg[2], volpos[3], vol_diff;
7955  if (pd != dummypoint) {
7956  if (pc != dummypoint) {
7957  volpos[0] = tetprismvol(pe, pd, pa, pb);
7958  volpos[1] = tetprismvol(pe, pd, pb, pc);
7959  volpos[2] = tetprismvol(pe, pd, pc, pa);
7960  volneg[0] = tetprismvol(pa, pb, pc, pd);
7961  volneg[1] = tetprismvol(pb, pa, pc, pe);
7962  } else { // pc == dummypoint
7963  volpos[0] = tetprismvol(pe, pd, pa, pb);
7964  volpos[1] = 0.;
7965  volpos[2] = 0.;
7966  volneg[0] = 0.;
7967  volneg[1] = 0.;
7968  }
7969  } else { // pd == dummypoint.
7970  volpos[0] = 0.;
7971  volpos[1] = 0.;
7972  volpos[2] = 0.;
7973  volneg[0] = 0.;
7974  volneg[1] = tetprismvol(pb, pa, pc, pe);
7975  }
7976  vol_diff = volpos[0] + volpos[1] + volpos[2] - volneg[0] - volneg[1];
7977  fc->tetprism_vol_sum += vol_diff; // Update the total sum.
7978  }
7979 
7980  // Bond three new tets together.
7981  for (i = 0; i < 3; i++) {
7982  esym(fliptets[i], newface);
7983  bond(newface, fliptets[(i + 1) % 3]);
7984  }
7985  // Bond to top outer boundary faces (at [a,b,c,d]).
7986  for (i = 0; i < 3; i++) {
7987  eorgoppo(fliptets[i], newface); // At edges [b,a], [c,b], [a,c].
7988  bond(newface, topcastets[i]);
7989  }
7990  // Bond bottom outer boundary faces (at [b,a,c,e]).
7991  for (i = 0; i < 3; i++) {
7992  edestoppo(fliptets[i], newface); // At edges [a,b], [b,c], [c,a].
7993  bond(newface, botcastets[i]);
7994  }
7995 
7996  if (checksubsegflag) {
7997  // Bond subsegments if there are.
7998  // Each new tet has 5 edges to be checked (except the edge [e,d]).
7999  face checkseg;
8000  // The middle three: [a,b], [b,c], [c,a].
8001  for (i = 0; i < 3; i++) {
8002  if (issubseg(topcastets[i])) {
8003  tsspivot1(topcastets[i], checkseg);
8004  eorgoppo(fliptets[i], newface);
8005  tssbond1(newface, checkseg);
8006  sstbond1(checkseg, newface);
8007  if (fc->chkencflag & 1) {
8008  enqueuesubface(badsubsegs, &checkseg);
8009  }
8010  }
8011  }
8012  // The top three: [d,a], [d,b], [d,c]. Two tets per edge.
8013  for (i = 0; i < 3; i++) {
8014  eprev(topcastets[i], casface);
8015  if (issubseg(casface)) {
8016  tsspivot1(casface, checkseg);
8017  enext(fliptets[i], newface);
8018  tssbond1(newface, checkseg);
8019  sstbond1(checkseg, newface);
8020  esym(fliptets[(i + 2) % 3], newface);
8021  eprevself(newface);
8022  tssbond1(newface, checkseg);
8023  sstbond1(checkseg, newface);
8024  if (fc->chkencflag & 1) {
8025  enqueuesubface(badsubsegs, &checkseg);
8026  }
8027  }
8028  }
8029  // The bot three: [a,e], [b,e], [c,e]. Two tets per edge.
8030  for (i = 0; i < 3; i++) {
8031  enext(botcastets[i], casface);
8032  if (issubseg(casface)) {
8033  tsspivot1(casface, checkseg);
8034  eprev(fliptets[i], newface);
8035  tssbond1(newface, checkseg);
8036  sstbond1(checkseg, newface);
8037  esym(fliptets[(i + 2) % 3], newface);
8038  enextself(newface);
8039  tssbond1(newface, checkseg);
8040  sstbond1(checkseg, newface);
8041  if (fc->chkencflag & 1) {
8042  enqueuesubface(badsubsegs, &checkseg);
8043  }
8044  }
8045  }
8046  } // if (checksubsegflag)
8047 
8048  if (checksubfaceflag) {
8049  // Bond 6 subfaces if there are.
8050  face checksh;
8051  for (i = 0; i < 3; i++) {
8052  if (issubface(topcastets[i])) {
8053  tspivot(topcastets[i], checksh);
8054  eorgoppo(fliptets[i], newface);
8055  sesymself(checksh);
8056  tsbond(newface, checksh);
8057  if (fc->chkencflag & 2) {
8058  enqueuesubface(badsubfacs, &checksh);
8059  }
8060  }
8061  }
8062  for (i = 0; i < 3; i++) {
8063  if (issubface(botcastets[i])) {
8064  tspivot(botcastets[i], checksh);
8065  edestoppo(fliptets[i], newface);
8066  sesymself(checksh);
8067  tsbond(newface, checksh);
8068  if (fc->chkencflag & 2) {
8069  enqueuesubface(badsubfacs, &checksh);
8070  }
8071  }
8072  }
8073  } // if (checksubfaceflag)
8074 
8075  if (fc->chkencflag & 4) {
8076  // Put three new tets into check list.
8077  for (i = 0; i < 3; i++) {
8078  enqueuetetrahedron(&(fliptets[i]));
8079  }
8080  }
8081 
8082  // Update the point-to-tet map.
8083  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
8084  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
8085  setpoint2tet(pc, (tetrahedron) fliptets[1].tet);
8086  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
8087  setpoint2tet(pe, (tetrahedron) fliptets[0].tet);
8088 
8089  if (hullflag > 0) {
8090  if (dummyflag != 0) {
8091  // Restore the original position of the points (for flipnm()).
8092  if (dummyflag == -1) {
8093  // Reverse the edge.
8094  for (i = 0; i < 3; i++) {
8095  esymself(fliptets[i]);
8096  }
8097  // Swap the last two new tets.
8098  newface = fliptets[1];
8099  fliptets[1] = fliptets[2];
8100  fliptets[2] = newface;
8101  } else {
8102  // either a or b were swapped.
8103  if (dummyflag == 1) {
8104  // a is dummypoint.
8105  newface = fliptets[0];
8106  fliptets[0] = fliptets[2];
8107  fliptets[2] = fliptets[1];
8108  fliptets[1] = newface;
8109  } else { // dummyflag == 2
8110  // b is dummypoint.
8111  newface = fliptets[0];
8112  fliptets[0] = fliptets[1];
8113  fliptets[1] = fliptets[2];
8114  fliptets[2] = newface;
8115  }
8116  }
8117  }
8118  }
8119 
8120  if (fc->enqflag > 0) {
8121  // Queue faces which may be locally non-Delaunay.
8122  for (i = 0; i < 3; i++) {
8123  eprevesym(fliptets[i], newface);
8124  flippush(flipstack, &newface);
8125  }
8126  if (fc->enqflag > 1) {
8127  for (i = 0; i < 3; i++) {
8128  enextesym(fliptets[i], newface);
8129  flippush(flipstack, &newface);
8130  }
8131  }
8132  }
8133 
8134  recenttet = fliptets[0];
8135 }
8136 
8138 // //
8139 // flip32() Perform a 3-to-2 flip (edge-to-face flip). //
8140 // //
8141 // 'fliptets' is an array of three tets (handles), which are [e,d,a,b], //
8142 // [e,d,b,c], and [e,d,c,a]. The two new tets: [a,b,c,d] and [b,a,c,e] are //
8143 // returned in [0] and [1] of 'fliptets'. As a result, the edge [e,d] is //
8144 // replaced by the face [a,b,c]. //
8145 // //
8146 // If 'hullflag' > 0, hull tets may be involved in this flip, i.e., one of //
8147 // the five vertices may be 'dummypoint'. There are two canonical cases: //
8148 // (1) d is 'dummypoint', then [a,b,c,d] is hull tet. If e is 'dummypoint',//
8149 // we reconfigure e to d, i.e., turnover it. //
8150 // (2) c is 'dummypoint' then both [a,b,c,d] and [b,a,c,e] are hull tets. //
8151 // If a or b is 'dummypoint', we reconfigure it to c, i.e., rotate the //
8152 // three old tets counterclockwisely (right-hand rule) until a or b //
8153 // is in c's position. //
8154 // //
8155 // If 'fc->enqflag' is set, convex hull faces will be queued for flipping. //
8156 // In particular, if 'fc->enqflag' is 1, it is called by incrementalflip() //
8157 // after the insertion of a new point. It is assumed that 'a' is the new //
8158 // point. In this case, only link faces of 'a' are queued. //
8159 // //
8160 // If 'checksubfaceflag' is on (global variable), and assume [e,d] is not a //
8161 // segment. There may be two (interior) subfaces sharing at [e,d], which are //
8162 // [e,d,p] and [e,d,q], where the pair (p,q) may be either (a,b), or (b,c), //
8163 // or (c,a) In such case, a 2-to-2 flip is performed on these two subfaces //
8164 // and two new subfaces [p,q,e] and [p,q,d] are created. They are inserted //
8165 // back into the tetrahedralization. //
8166 // //
8168 
8169 void tetgenmesh::flip32(triface* fliptets, int hullflag, flipconstraints *fc)
8170 {
8171  triface topcastets[3], botcastets[3];
8172  triface newface, casface;
8173  face flipshs[3];
8174  face checkseg;
8175  point pa, pb, pc, pd, pe;
8176  REAL attrib, volume;
8177  int dummyflag = 0; // Rangle = {-1, 0, 1, 2}
8178  int spivot = -1, scount = 0; // for flip22()
8179  int t1ver;
8180  int i, j;
8181 
8182  if (hullflag > 0) {
8183  // Check if e is 'dummypoint'.
8184  if (org(fliptets[0]) == dummypoint) {
8185  // Reverse the edge.
8186  for (i = 0; i < 3; i++) {
8187  esymself(fliptets[i]);
8188  }
8189  // Swap the last two tets.
8190  newface = fliptets[1];
8191  fliptets[1] = fliptets[2];
8192  fliptets[2] = newface;
8193  dummyflag = -1; // e is dummypoint.
8194  } else {
8195  // Check if a or b is the 'dummypoint'.
8196  if (apex(fliptets[0]) == dummypoint) {
8197  dummyflag = 1; // a is dummypoint.
8198  newface = fliptets[0];
8199  fliptets[0] = fliptets[1];
8200  fliptets[1] = fliptets[2];
8201  fliptets[2] = newface;
8202  } else if (apex(fliptets[1]) == dummypoint) {
8203  dummyflag = 2; // b is dummypoint.
8204  newface = fliptets[0];
8205  fliptets[0] = fliptets[2];
8206  fliptets[2] = fliptets[1];
8207  fliptets[1] = newface;
8208  } else {
8209  dummyflag = 0; // either c or d may be dummypoint.
8210  }
8211  }
8212  }
8213 
8214  pa = apex(fliptets[0]);
8215  pb = apex(fliptets[1]);
8216  pc = apex(fliptets[2]);
8217  pd = dest(fliptets[0]);
8218  pe = org(fliptets[0]);
8219 
8220  flip32count++;
8221 
8222  // Get the outer boundary faces.
8223  for (i = 0; i < 3; i++) {
8224  eorgoppo(fliptets[i], casface);
8225  fsym(casface, topcastets[i]);
8226  }
8227  for (i = 0; i < 3; i++) {
8228  edestoppo(fliptets[i], casface);
8229  fsym(casface, botcastets[i]);
8230  }
8231 
8232  if (checksubfaceflag) {
8233  // Check if there are interior subfaces at the edge [e,d].
8234  for (i = 0; i < 3; i++) {
8235  tspivot(fliptets[i], flipshs[i]);
8236  if (flipshs[i].sh != NULL) {
8237  // Found an interior subface.
8238  stdissolve(flipshs[i]); // Disconnect the sub-tet bond.
8239  scount++;
8240  } else {
8241  spivot = i;
8242  }
8243  }
8244  }
8245 
8246  // Re-use fliptets[0] and fliptets[1].
8247  fliptets[0].ver = 11;
8248  fliptets[1].ver = 11;
8249  setelemmarker(fliptets[0].tet, 0); // Clear all flags.
8250  setelemmarker(fliptets[1].tet, 0);
8251  if (checksubsegflag) {
8252  // Dealloc the space to subsegments.
8253  if (fliptets[0].tet[8] != NULL) {
8254  tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
8255  fliptets[0].tet[8] = NULL;
8256  }
8257  if (fliptets[1].tet[8] != NULL) {
8258  tet2segpool->dealloc((shellface *) fliptets[1].tet[8]);
8259  fliptets[1].tet[8] = NULL;
8260  }
8261  }
8262  if (checksubfaceflag) {
8263  // Dealloc the space to subfaces.
8264  if (fliptets[0].tet[9] != NULL) {
8265  tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
8266  fliptets[0].tet[9] = NULL;
8267  }
8268  if (fliptets[1].tet[9] != NULL) {
8269  tet2subpool->dealloc((shellface *) fliptets[1].tet[9]);
8270  fliptets[1].tet[9] = NULL;
8271  }
8272  }
8273  if (checksubfaceflag) {
8274  if (scount > 0) {
8275  // The element attributes and volume constraint must be set correctly.
8276  // There are two subfaces involved in this flip. The three tets are
8277  // separated into two different regions, one may be exterior. The
8278  // first region has two tets, and the second region has only one.
8279  // The two created tets must be in the same region as the first region.
8280  // The element attributes and volume constraint must be set correctly.
8281  //assert(spivot != -1);
8282  // The tet fliptets[spivot] is in the first region.
8283  for (j = 0; j < 2; j++) {
8284  for (i = 0; i < numelemattrib; i++) {
8285  attrib = elemattribute(fliptets[spivot].tet, i);
8286  setelemattribute(fliptets[j].tet, i, attrib);
8287  }
8288  if (b->varvolume) {
8289  volume = volumebound(fliptets[spivot].tet);
8290  setvolumebound(fliptets[j].tet, volume);
8291  }
8292  }
8293  }
8294  }
8295  // Delete an old tet.
8296  tetrahedrondealloc(fliptets[2].tet);
8297 
8298  if (hullflag > 0) {
8299  // Check if c is dummypointc.
8300  if (pc != dummypoint) {
8301  // Check if d is dummypoint.
8302  if (pd != dummypoint) {
8303  // No hull tet is involved.
8304  } else {
8305  // We deleted three hull tets, and created one hull tet.
8306  hullsize -= 2;
8307  }
8308  setvertices(fliptets[0], pa, pb, pc, pd);
8309  setvertices(fliptets[1], pb, pa, pc, pe);
8310  } else {
8311  // c is dummypoint. The two new tets are hull tets.
8312  setvertices(fliptets[0], pb, pa, pd, pc);
8313  setvertices(fliptets[1], pa, pb, pe, pc);
8314  // Adjust badc -> abcd.
8315  esymself(fliptets[0]);
8316  // Adjust abec -> bace.
8317  esymself(fliptets[1]);
8318  // The hullsize does not change.
8319  }
8320  } else {
8321  setvertices(fliptets[0], pa, pb, pc, pd);
8322  setvertices(fliptets[1], pb, pa, pc, pe);
8323  }
8324 
8325  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
8326  REAL volneg[3], volpos[2], vol_diff;
8327  if (pc != dummypoint) {
8328  if (pd != dummypoint) {
8329  volneg[0] = tetprismvol(pe, pd, pa, pb);
8330  volneg[1] = tetprismvol(pe, pd, pb, pc);
8331  volneg[2] = tetprismvol(pe, pd, pc, pa);
8332  volpos[0] = tetprismvol(pa, pb, pc, pd);
8333  volpos[1] = tetprismvol(pb, pa, pc, pe);
8334  } else { // pd == dummypoint
8335  volneg[0] = 0.;
8336  volneg[1] = 0.;
8337  volneg[2] = 0.;
8338  volpos[0] = 0.;
8339  volpos[1] = tetprismvol(pb, pa, pc, pe);
8340  }
8341  } else { // pc == dummypoint.
8342  volneg[0] = tetprismvol(pe, pd, pa, pb);
8343  volneg[1] = 0.;
8344  volneg[2] = 0.;
8345  volpos[0] = 0.;
8346  volpos[1] = 0.;
8347  }
8348  vol_diff = volpos[0] + volpos[1] - volneg[0] - volneg[1] - volneg[2];
8349  fc->tetprism_vol_sum += vol_diff; // Update the total sum.
8350  }
8351 
8352  // Bond abcd <==> bace.
8353  bond(fliptets[0], fliptets[1]);
8354  // Bond new faces to top outer boundary faces (at abcd).
8355  for (i = 0; i < 3; i++) {
8356  esym(fliptets[0], newface);
8357  bond(newface, topcastets[i]);
8358  enextself(fliptets[0]);
8359  }
8360  // Bond new faces to bottom outer boundary faces (at bace).
8361  for (i = 0; i < 3; i++) {
8362  esym(fliptets[1], newface);
8363  bond(newface, botcastets[i]);
8364  eprevself(fliptets[1]);
8365  }
8366 
8367  if (checksubsegflag) {
8368  // Bond 9 segments to new (flipped) tets.
8369  for (i = 0; i < 3; i++) { // edges a->b, b->c, c->a.
8370  if (issubseg(topcastets[i])) {
8371  tsspivot1(topcastets[i], checkseg);
8372  tssbond1(fliptets[0], checkseg);
8373  sstbond1(checkseg, fliptets[0]);
8374  tssbond1(fliptets[1], checkseg);
8375  sstbond1(checkseg, fliptets[1]);
8376  if (fc->chkencflag & 1) {
8377  enqueuesubface(badsubsegs, &checkseg);
8378  }
8379  }
8380  enextself(fliptets[0]);
8381  eprevself(fliptets[1]);
8382  }
8383  // The three top edges.
8384  for (i = 0; i < 3; i++) { // edges b->d, c->d, a->d.
8385  esym(fliptets[0], newface);
8386  eprevself(newface);
8387  enext(topcastets[i], casface);
8388  if (issubseg(casface)) {
8389  tsspivot1(casface, checkseg);
8390  tssbond1(newface, checkseg);
8391  sstbond1(checkseg, newface);
8392  if (fc->chkencflag & 1) {
8393  enqueuesubface(badsubsegs, &checkseg);
8394  }
8395  }
8396  enextself(fliptets[0]);
8397  }
8398  // The three bot edges.
8399  for (i = 0; i < 3; i++) { // edges b<-e, c<-e, a<-e.
8400  esym(fliptets[1], newface);
8401  enextself(newface);
8402  eprev(botcastets[i], casface);
8403  if (issubseg(casface)) {
8404  tsspivot1(casface, checkseg);
8405  tssbond1(newface, checkseg);
8406  sstbond1(checkseg, newface);
8407  if (fc->chkencflag & 1) {
8408  enqueuesubface(badsubsegs, &checkseg);
8409  }
8410  }
8411  eprevself(fliptets[1]);
8412  }
8413  } // if (checksubsegflag)
8414 
8415  if (checksubfaceflag) {
8416  face checksh;
8417  // Bond the top three casing subfaces.
8418  for (i = 0; i < 3; i++) { // At edges [b,a], [c,b], [a,c]
8419  if (issubface(topcastets[i])) {
8420  tspivot(topcastets[i], checksh);
8421  esym(fliptets[0], newface);
8422  sesymself(checksh);
8423  tsbond(newface, checksh);
8424  if (fc->chkencflag & 2) {
8425  enqueuesubface(badsubfacs, &checksh);
8426  }
8427  }
8428  enextself(fliptets[0]);
8429  }
8430  // Bond the bottom three casing subfaces.
8431  for (i = 0; i < 3; i++) { // At edges [a,b], [b,c], [c,a]
8432  if (issubface(botcastets[i])) {
8433  tspivot(botcastets[i], checksh);
8434  esym(fliptets[1], newface);
8435  sesymself(checksh);
8436  tsbond(newface, checksh);
8437  if (fc->chkencflag & 2) {
8438  enqueuesubface(badsubfacs, &checksh);
8439  }
8440  }
8441  eprevself(fliptets[1]);
8442  }
8443 
8444  if (scount > 0) {
8445  face flipfaces[2];
8446  // Perform a 2-to-2 flip in subfaces.
8447  flipfaces[0] = flipshs[(spivot + 1) % 3];
8448  flipfaces[1] = flipshs[(spivot + 2) % 3];
8449  sesymself(flipfaces[1]);
8450  flip22(flipfaces, 0, fc->chkencflag);
8451  // Connect the flipped subfaces to flipped tets.
8452  // First go to the corresponding flipping edge.
8453  // Re-use top- and botcastets[0].
8454  topcastets[0] = fliptets[0];
8455  botcastets[0] = fliptets[1];
8456  for (i = 0; i < ((spivot + 1) % 3); i++) {
8457  enextself(topcastets[0]);
8458  eprevself(botcastets[0]);
8459  }
8460  // Connect the top subface to the top tets.
8461  esymself(topcastets[0]);
8462  sesymself(flipfaces[0]);
8463  // Check if there already exists a subface.
8464  tspivot(topcastets[0], checksh);
8465  if (checksh.sh == NULL) {
8466  tsbond(topcastets[0], flipfaces[0]);
8467  fsymself(topcastets[0]);
8468  sesymself(flipfaces[0]);
8469  tsbond(topcastets[0], flipfaces[0]);
8470  } else {
8471  // An invalid 2-to-2 flip. Report a bug.
8472  terminatetetgen(this, 2);
8473  }
8474  // Connect the bot subface to the bottom tets.
8475  esymself(botcastets[0]);
8476  sesymself(flipfaces[1]);
8477  // Check if there already exists a subface.
8478  tspivot(botcastets[0], checksh);
8479  if (checksh.sh == NULL) {
8480  tsbond(botcastets[0], flipfaces[1]);
8481  fsymself(botcastets[0]);
8482  sesymself(flipfaces[1]);
8483  tsbond(botcastets[0], flipfaces[1]);
8484  } else {
8485  // An invalid 2-to-2 flip. Report a bug.
8486  terminatetetgen(this, 2);
8487  }
8488  } // if (scount > 0)
8489  } // if (checksubfaceflag)
8490 
8491  if (fc->chkencflag & 4) {
8492  // Put two new tets into check list.
8493  for (i = 0; i < 2; i++) {
8494  enqueuetetrahedron(&(fliptets[i]));
8495  }
8496  }
8497 
8498  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
8499  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
8500  setpoint2tet(pc, (tetrahedron) fliptets[0].tet);
8501  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
8502  setpoint2tet(pe, (tetrahedron) fliptets[1].tet);
8503 
8504  if (hullflag > 0) {
8505  if (dummyflag != 0) {
8506  // Restore the original position of the points (for flipnm()).
8507  if (dummyflag == -1) {
8508  // e were dummypoint. Swap the two new tets.
8509  newface = fliptets[0];
8510  fliptets[0] = fliptets[1];
8511  fliptets[1] = newface;
8512  } else {
8513  // a or b was dummypoint.
8514  if (dummyflag == 1) {
8515  eprevself(fliptets[0]);
8516  enextself(fliptets[1]);
8517  } else { // dummyflag == 2
8518  enextself(fliptets[0]);
8519  eprevself(fliptets[1]);
8520  }
8521  }
8522  }
8523  }
8524 
8525  if (fc->enqflag > 0) {
8526  // Queue faces which may be locally non-Delaunay.
8527  // pa = org(fliptets[0]); // 'a' may be a new vertex.
8528  enextesym(fliptets[0], newface);
8529  flippush(flipstack, &newface);
8530  eprevesym(fliptets[1], newface);
8531  flippush(flipstack, &newface);
8532  if (fc->enqflag > 1) {
8533  //pb = dest(fliptets[0]);
8534  eprevesym(fliptets[0], newface);
8535  flippush(flipstack, &newface);
8536  enextesym(fliptets[1], newface);
8537  flippush(flipstack, &newface);
8538  //pc = apex(fliptets[0]);
8539  esym(fliptets[0], newface);
8540  flippush(flipstack, &newface);
8541  esym(fliptets[1], newface);
8542  flippush(flipstack, &newface);
8543  }
8544  }
8545 
8546  recenttet = fliptets[0];
8547 }
8548 
8550 // //
8551 // flip41() Perform a 4-to-1 flip (Remove a vertex). //
8552 // //
8553 // 'fliptets' is an array of four tetrahedra in the star of the removing //
8554 // vertex 'p'. Let the four vertices in the star of p be a, b, c, and d. The //
8555 // four tets in 'fliptets' are: [p,d,a,b], [p,d,b,c], [p,d,c,a], and [a,b,c, //
8556 // p]. On return, 'fliptets[0]' is the new tet [a,b,c,d]. //
8557 // //
8558 // If 'hullflag' is set (> 0), one of the five vertices may be 'dummypoint'. //
8559 // The 'hullsize' may be changed. Note that p may be dummypoint. In this //
8560 // case, four hull tets are replaced by one real tet. //
8561 // //
8562 // If 'checksubface' flag is set (>0), it is possible that there are three //
8563 // interior subfaces connecting at p. If so, a 3-to-1 flip is performed to //
8564 // to remove p from the surface triangulation. //
8565 // //
8566 // If it is called by the routine incrementalflip(), we assume that d is the //
8567 // newly inserted vertex. //
8568 // //
8570 
8571 void tetgenmesh::flip41(triface* fliptets, int hullflag, flipconstraints *fc)
8572 {
8573  triface topcastets[3], botcastet;
8574  triface newface, neightet;
8575  face flipshs[4];
8576  point pa, pb, pc, pd, pp;
8577  int dummyflag = 0; // in {0, 1, 2, 3, 4}
8578  int spivot = -1, scount = 0;
8579  int t1ver;
8580  int i;
8581 
8582  pa = org(fliptets[3]);
8583  pb = dest(fliptets[3]);
8584  pc = apex(fliptets[3]);
8585  pd = dest(fliptets[0]);
8586  pp = org(fliptets[0]); // The removing vertex.
8587 
8588  flip41count++;
8589 
8590  // Get the outer boundary faces.
8591  for (i = 0; i < 3; i++) {
8592  enext(fliptets[i], topcastets[i]);
8593  fnextself(topcastets[i]); // [d,a,b,#], [d,b,c,#], [d,c,a,#]
8594  enextself(topcastets[i]); // [a,b,d,#], [b,c,d,#], [c,a,d,#]
8595  }
8596  fsym(fliptets[3], botcastet); // [b,a,c,#]
8597 
8598  if (checksubfaceflag) {
8599  // Check if there are three subfaces at 'p'.
8600  // Re-use 'newface'.
8601  for (i = 0; i < 3; i++) {
8602  fnext(fliptets[3], newface); // [a,b,p,d],[b,c,p,d],[c,a,p,d].
8603  tspivot(newface, flipshs[i]);
8604  if (flipshs[i].sh != NULL) {
8605  spivot = i; // Remember this subface.
8606  scount++;
8607  }
8608  enextself(fliptets[3]);
8609  }
8610  if (scount > 0) {
8611  // There are three subfaces connecting at p.
8612  if (scount < 3) {
8613  // The new subface is one of {[a,b,d], [b,c,d], [c,a,d]}.
8614  // Go to the tet containing the three subfaces.
8615  fsym(topcastets[spivot], neightet);
8616  // Get the three subfaces connecting at p.
8617  for (i = 0; i < 3; i++) {
8618  esym(neightet, newface);
8619  tspivot(newface, flipshs[i]);
8620  eprevself(neightet);
8621  }
8622  } else {
8623  spivot = 3; // The new subface is [a,b,c].
8624  }
8625  }
8626  } // if (checksubfaceflag)
8627 
8628 
8629  // Re-use fliptets[0] for [a,b,c,d].
8630  fliptets[0].ver = 11;
8631  setelemmarker(fliptets[0].tet, 0); // Clean all flags.
8632  // NOTE: the element attributes and volume constraint remain unchanged.
8633  if (checksubsegflag) {
8634  // Dealloc the space to subsegments.
8635  if (fliptets[0].tet[8] != NULL) {
8636  tet2segpool->dealloc((shellface *) fliptets[0].tet[8]);
8637  fliptets[0].tet[8] = NULL;
8638  }
8639  }
8640  if (checksubfaceflag) {
8641  // Dealloc the space to subfaces.
8642  if (fliptets[0].tet[9] != NULL) {
8643  tet2subpool->dealloc((shellface *) fliptets[0].tet[9]);
8644  fliptets[0].tet[9] = NULL;
8645  }
8646  }
8647  // Delete the other three tets.
8648  for (i = 1; i < 4; i++) {
8649  tetrahedrondealloc(fliptets[i].tet);
8650  }
8651 
8652  if (pp != dummypoint) {
8653  // Mark the point pp as unused.
8654  setpointtype(pp, UNUSEDVERTEX);
8655  unuverts++;
8656  }
8657 
8658  // Create the new tet [a,b,c,d].
8659  if (hullflag > 0) {
8660  // One of the five vertices may be 'dummypoint'.
8661  if (pa == dummypoint) {
8662  // pa is dummypoint.
8663  setvertices(fliptets[0], pc, pb, pd, pa);
8664  esymself(fliptets[0]); // [b,c,a,d]
8665  eprevself(fliptets[0]); // [a,b,c,d]
8666  dummyflag = 1;
8667  } else if (pb == dummypoint) {
8668  setvertices(fliptets[0], pa, pc, pd, pb);
8669  esymself(fliptets[0]); // [c,a,b,d]
8670  enextself(fliptets[0]); // [a,b,c,d]
8671  dummyflag = 2;
8672  } else if (pc == dummypoint) {
8673  setvertices(fliptets[0], pb, pa, pd, pc);
8674  esymself(fliptets[0]); // [a,b,c,d]
8675  dummyflag = 3;
8676  } else if (pd == dummypoint) {
8677  setvertices(fliptets[0], pa, pb, pc, pd);
8678  dummyflag = 4;
8679  } else {
8680  setvertices(fliptets[0], pa, pb, pc, pd);
8681  if (pp == dummypoint) {
8682  dummyflag = -1;
8683  } else {
8684  dummyflag = 0;
8685  }
8686  }
8687  if (dummyflag > 0) {
8688  // We deleted 3 hull tets, and create 1 hull tet.
8689  hullsize -= 2;
8690  } else if (dummyflag < 0) {
8691  // We deleted 4 hull tets.
8692  hullsize -= 4;
8693  // meshedges does not change.
8694  }
8695  } else {
8696  setvertices(fliptets[0], pa, pb, pc, pd);
8697  }
8698 
8699  if (fc->remove_ndelaunay_edge) { // calc_tetprism_vol
8700  REAL volneg[4], volpos[1], vol_diff;
8701  if (dummyflag > 0) {
8702  if (pa == dummypoint) {
8703  volneg[0] = 0.;
8704  volneg[1] = tetprismvol(pp, pd, pb, pc);
8705  volneg[2] = 0.;
8706  volneg[3] = 0.;
8707  } else if (pb == dummypoint) {
8708  volneg[0] = 0.;
8709  volneg[1] = 0.;
8710  volneg[2] = tetprismvol(pp, pd, pc, pa);
8711  volneg[3] = 0.;
8712  } else if (pc == dummypoint) {
8713  volneg[0] = tetprismvol(pp, pd, pa, pb);
8714  volneg[1] = 0.;
8715  volneg[2] = 0.;
8716  volneg[3] = 0.;
8717  } else { // pd == dummypoint
8718  volneg[0] = 0.;
8719  volneg[1] = 0.;
8720  volneg[2] = 0.;
8721  volneg[3] = tetprismvol(pa, pb, pc, pp);
8722  }
8723  volpos[0] = 0.;
8724  } else if (dummyflag < 0) {
8725  volneg[0] = 0.;
8726  volneg[1] = 0.;
8727  volneg[2] = 0.;
8728  volneg[3] = 0.;
8729  volpos[0] = tetprismvol(pa, pb, pc, pd);
8730  } else {
8731  volneg[0] = tetprismvol(pp, pd, pa, pb);
8732  volneg[1] = tetprismvol(pp, pd, pb, pc);
8733  volneg[2] = tetprismvol(pp, pd, pc, pa);
8734  volneg[3] = tetprismvol(pa, pb, pc, pp);
8735  volpos[0] = tetprismvol(pa, pb, pc, pd);
8736  }
8737  vol_diff = volpos[0] - volneg[0] - volneg[1] - volneg[2] - volneg[3];
8738  fc->tetprism_vol_sum += vol_diff; // Update the total sum.
8739  }
8740 
8741  // Bond the new tet to adjacent tets.
8742  for (i = 0; i < 3; i++) {
8743  esym(fliptets[0], newface); // At faces [b,a,d], [c,b,d], [a,c,d].
8744  bond(newface, topcastets[i]);
8745  enextself(fliptets[0]);
8746  }
8747  bond(fliptets[0], botcastet);
8748 
8749  if (checksubsegflag) {
8750  face checkseg;
8751  // Bond 6 segments (at edges of [a,b,c,d]) if there there are.
8752  for (i = 0; i < 3; i++) {
8753  eprev(topcastets[i], newface); // At edges [d,a],[d,b],[d,c].
8754  if (issubseg(newface)) {
8755  tsspivot1(newface, checkseg);
8756  esym(fliptets[0], newface);
8757  enextself(newface); // At edges [a,d], [b,d], [c,d].
8758  tssbond1(newface, checkseg);
8759  sstbond1(checkseg, newface);
8760  if (fc->chkencflag & 1) {
8761  enqueuesubface(badsubsegs, &checkseg);
8762  }
8763  }
8764  enextself(fliptets[0]);
8765  }
8766  for (i = 0; i < 3; i++) {
8767  if (issubseg(topcastets[i])) {
8768  tsspivot1(topcastets[i], checkseg); // At edges [a,b],[b,c],[c,a].
8769  tssbond1(fliptets[0], checkseg);
8770  sstbond1(checkseg, fliptets[0]);
8771  if (fc->chkencflag & 1) {
8772  enqueuesubface(badsubsegs, &checkseg);
8773  }
8774  }
8775  enextself(fliptets[0]);
8776  }
8777  }
8778 
8779  if (checksubfaceflag) {
8780  face checksh;
8781  // Bond 4 subfaces (at faces of [a,b,c,d]) if there are.
8782  for (i = 0; i < 3; i++) {
8783  if (issubface(topcastets[i])) {
8784  tspivot(topcastets[i], checksh); // At faces [a,b,d],[b,c,d],[c,a,d]
8785  esym(fliptets[0], newface); // At faces [b,a,d],[c,b,d],[a,c,d]
8786  sesymself(checksh);
8787  tsbond(newface, checksh);
8788  if (fc->chkencflag & 2) {
8789  enqueuesubface(badsubfacs, &checksh);
8790  }
8791  }
8792  enextself(fliptets[0]);
8793  }
8794  if (issubface(botcastet)) {
8795  tspivot(botcastet, checksh); // At face [b,a,c]
8796  sesymself(checksh);
8797  tsbond(fliptets[0], checksh);
8798  if (fc->chkencflag & 2) {
8799  enqueuesubface(badsubfacs, &checksh);
8800  }
8801  }
8802 
8803  if (spivot >= 0) {
8804  // Perform a 3-to-1 flip in surface triangulation.
8805  // Depending on the value of 'spivot', the three subfaces are:
8806  // - 0: [a,b,p], [b,d,p], [d,a,p]
8807  // - 1: [b,c,p], [c,d,p], [d,b,p]
8808  // - 2: [c,a,p], [a,d,p], [d,c,p]
8809  // - 3: [a,b,p], [b,c,p], [c,a,p]
8810  // Adjust the three subfaces such that their origins are p, i.e.,
8811  // - 3: [p,a,b], [p,b,c], [p,c,a]. (Required by the flip31()).
8812  for (i = 0; i < 3; i++) {
8813  senext2self(flipshs[i]);
8814  }
8815  flip31(flipshs, 0);
8816  // Delete the three old subfaces.
8817  for (i = 0; i < 3; i++) {
8818  shellfacedealloc(subfaces, flipshs[i].sh);
8819  }
8820  if (spivot < 3) {
8821  // // Bond the new subface to the new tet [a,b,c,d].
8822  tsbond(topcastets[spivot], flipshs[3]);
8823  fsym(topcastets[spivot], newface);
8824  sesym(flipshs[3], checksh);
8825  tsbond(newface, checksh);
8826  } else {
8827  // Bound the new subface [a,b,c] to the new tet [a,b,c,d].
8828  tsbond(fliptets[0], flipshs[3]);
8829  fsym(fliptets[0], newface);
8830  sesym(flipshs[3], checksh);
8831  tsbond(newface, checksh);
8832  }
8833  } // if (spivot > 0)
8834  } // if (checksubfaceflag)
8835 
8836  if (fc->chkencflag & 4) {
8837  enqueuetetrahedron(&(fliptets[0]));
8838  }
8839 
8840  // Update the point-to-tet map.
8841  setpoint2tet(pa, (tetrahedron) fliptets[0].tet);
8842  setpoint2tet(pb, (tetrahedron) fliptets[0].tet);
8843  setpoint2tet(pc, (tetrahedron) fliptets[0].tet);
8844  setpoint2tet(pd, (tetrahedron) fliptets[0].tet);
8845 
8846  if (fc->enqflag > 0) {
8847  // Queue faces which may be locally non-Delaunay.
8848  flippush(flipstack, &(fliptets[0])); // [a,b,c] (opposite to new point).
8849  if (fc->enqflag > 1) {
8850  for (i = 0; i < 3; i++) {
8851  esym(fliptets[0], newface);
8852  flippush(flipstack, &newface);
8853  enextself(fliptets[0]);
8854  }
8855  }
8856  }
8857 
8858  recenttet = fliptets[0];
8859 }
8860 
8862 // //
8863 // flipnm() Flip an edge through a sequence of elementary flips. //
8864 // //
8865 // 'abtets' is an array of 'n' tets in the star of edge [a,b].These tets are //
8866 // ordered in a counterclockwise cycle with respect to the vector a->b, i.e.,//
8867 // use the right-hand rule. //
8868 // //
8869 // 'level' (>= 0) indicates the current link level. If 'level > 0', we are //
8870 // flipping a link edge of an edge [a',b'], and 'abedgepivot' indicates //
8871 // which link edge, i.e., [c',b'] or [a',c'], is [a,b] These two parameters //
8872 // allow us to determine the new tets after a 3-to-2 flip, i.e., tets that //
8873 // do not inside the reduced star of edge [a',b']. //
8874 // //
8875 // If the flag 'fc->unflip' is set, this routine un-does the flips performed //
8876 // in flipnm([a,b]) so that the mesh is returned to its original state //
8877 // before doing the flipnm([a,b]) operation. //
8878 // //
8879 // The return value is an integer nn, where nn <= n. If nn is 2, then the //
8880 // edge is flipped. The first and the second tets in 'abtets' are new tets. //
8881 // Otherwise, nn > 2, the edge is not flipped, and nn is the number of tets //
8882 // in the current star of [a,b]. //
8883 // //
8884 // ASSUMPTIONS: //
8885 // - Neither a nor b is 'dummypoint'. //
8886 // - [a,b] must not be a segment. //
8887 // //
8889 
8890 int tetgenmesh::flipnm(triface* abtets, int n, int level, int abedgepivot,
8891  flipconstraints* fc)
8892 {
8893  triface fliptets[3], spintet, flipedge;
8894  triface *tmpabtets, *parytet;
8895  point pa, pb, pc, pd, pe, pf;
8896  REAL ori;
8897  int hullflag, hulledgeflag;
8898  int reducflag, rejflag;
8899  int reflexlinkedgecount;
8900  int edgepivot;
8901  int n1, nn;
8902  int t1ver;
8903  int i, j;
8904 
8905  pa = org(abtets[0]);
8906  pb = dest(abtets[0]);
8907 
8908  if (n > 3) {
8909  // Try to reduce the size of the Star(ab) by flipping a face in it.
8910  reflexlinkedgecount = 0;
8911 
8912  for (i = 0; i < n; i++) {
8913  // Let the face of 'abtets[i]' be [a,b,c].
8914  if (checksubfaceflag) {
8915  if (issubface(abtets[i])) {
8916  continue; // Skip a subface.
8917  }
8918  }
8919  // Do not flip this face if it is involved in two Stars.
8920  if ((elemcounter(abtets[i]) > 1) ||
8921  (elemcounter(abtets[(i - 1 + n) % n]) > 1)) {
8922  continue;
8923  }
8924 
8925  pc = apex(abtets[i]);
8926  pd = apex(abtets[(i + 1) % n]);
8927  pe = apex(abtets[(i - 1 + n) % n]);
8928  if ((pd == dummypoint) || (pe == dummypoint)) {
8929  continue; // [a,b,c] is a hull face.
8930  }
8931 
8932 
8933  // Decide whether [a,b,c] is flippable or not.
8934  reducflag = 0;
8935 
8936  hullflag = (pc == dummypoint); // pc may be dummypoint.
8937  hulledgeflag = 0;
8938  if (hullflag == 0) {
8939  ori = orient3d(pb, pc, pd, pe); // Is [b,c] locally convex?
8940  if (ori > 0) {
8941  ori = orient3d(pc, pa, pd, pe); // Is [c,a] locally convex?
8942  if (ori > 0) {
8943  // Test if [a,b] is locally convex OR flat.
8944  ori = orient3d(pa, pb, pd, pe);
8945  if (ori > 0) {
8946  // Found a 2-to-3 flip: [a,b,c] => [e,d]
8947  reducflag = 1;
8948  } else if (ori == 0) {
8949  // [a,b] is flat.
8950  if (n == 4) {
8951  // The "flat" tet can be removed immediately by a 3-to-2 flip.
8952  reducflag = 1;
8953  // Check if [e,d] is a hull edge.
8954  pf = apex(abtets[(i + 2) % n]);
8955  hulledgeflag = (pf == dummypoint);
8956  }
8957  }
8958  }
8959  }
8960  if (!reducflag) {
8961  reflexlinkedgecount++;
8962  }
8963  } else {
8964  // 'c' is dummypoint.
8965  if (n == 4) {
8966  // Let the vertex opposite to 'c' is 'f'.
8967  // A 4-to-4 flip is possible if the two tets [d,e,f,a] and [e,d,f,b]
8968  // are valid tets.
8969  // Note: When the mesh is not convex, it is possible that [a,b] is
8970  // locally non-convex (at hull faces [a,b,e] and [b,a,d]).
8971  // In this case, an edge flip [a,b] to [e,d] is still possible.
8972  pf = apex(abtets[(i + 2) % n]);
8973  ori = orient3d(pd, pe, pf, pa);
8974  if (ori < 0) {
8975  ori = orient3d(pe, pd, pf, pb);
8976  if (ori < 0) {
8977  // Found a 4-to-4 flip: [a,b] => [e,d]
8978  reducflag = 1;
8979  ori = 0; // Signal as a 4-to-4 flip (like a co-planar case).
8980  hulledgeflag = 1; // [e,d] is a hull edge.
8981  }
8982  }
8983  }
8984  } // if (hullflag)
8985 
8986  if (reducflag) {
8987  if (nonconvex && hulledgeflag) {
8988  // We will create a hull edge [e,d]. Make sure it does not exist.
8989  if (getedge(pe, pd, &spintet)) {
8990  // The 2-to-3 flip is not a topological valid flip.
8991  reducflag = 0;
8992  }
8993  }
8994  }
8995 
8996  if (reducflag) {
8997  // [a,b,c] could be removed by a 2-to-3 flip.
8998  rejflag = 0;
8999  if (fc->checkflipeligibility) {
9000  // Check if the flip can be performed.
9001  rejflag = checkflipeligibility(1, pa, pb, pc, pd, pe, level,
9002  abedgepivot, fc);
9003  }
9004  if (!rejflag) {
9005  // Do flip: [a,b,c] => [e,d].
9006  fliptets[0] = abtets[i];
9007  fsym(fliptets[0], fliptets[1]); // abtets[i-1].
9008  flip23(fliptets, hullflag, fc);
9009 
9010  // Shrink the array 'abtets', maintain the original order.
9011  // Two tets 'abtets[i-1] ([a,b,e,c])' and 'abtets[i] ([a,b,c,d])'
9012  // are flipped, i.e., they do not in Star(ab) anymore.
9013  // 'fliptets[0]' ([e,d,a,b]) is in Star(ab), it is saved in
9014  // 'abtets[i-1]' (adjust it to be [a,b,e,d]), see below:
9015  //
9016  // before after
9017  // [0] |___________| [0] |___________|
9018  // ... |___________| ... |___________|
9019  // [i-1] |_[a,b,e,c]_| [i-1] |_[a,b,e,d]_|
9020  // [i] |_[a,b,c,d]_| --> [i] |_[a,b,d,#]_|
9021  // [i+1] |_[a,b,d,#]_| [i+1] |_[a,b,#,*]_|
9022  // ... |___________| ... |___________|
9023  // [n-2] |___________| [n-2] |___________|
9024  // [n-1] |___________| [n-1] |_[i]_2-t-3_|
9025  //
9026  edestoppoself(fliptets[0]); // [a,b,e,d]
9027  // Increase the counter of this new tet (it is in Star(ab)).
9028  increaseelemcounter(fliptets[0]);
9029  abtets[(i - 1 + n) % n] = fliptets[0];
9030  for (j = i; j < n - 1; j++) {
9031  abtets[j] = abtets[j + 1]; // Upshift
9032  }
9033  // The last entry 'abtets[n-1]' is empty. It is used in two ways:
9034  // (i) it remembers the vertex 'c' (in 'abtets[n-1].tet'), and
9035  // (ii) it remembers the position [i] where this flip took place.
9036  // These information let us to either undo this flip or recover
9037  // the original edge link (for collecting new created tets).
9038  abtets[n - 1].tet = (tetrahedron *) pc;
9039  abtets[n - 1].ver = 0; // Clear it.
9040  // 'abtets[n - 1].ver' is in range [0,11] -- only uses 4 bits.
9041  // Use the 5th bit in 'abtets[n - 1].ver' to signal a 2-to-3 flip.
9042  abtets[n - 1].ver |= (1 << 4);
9043  // The poisition [i] of this flip is saved above the 7th bit.
9044  abtets[n - 1].ver |= (i << 6);
9045 
9046  if (fc->collectnewtets) {
9047  // Push the two new tets [e,d,b,c] and [e,d,c,a] into a stack.
9048  // Re-use the global array 'cavetetlist'.
9049  for (j = 1; j < 3; j++) {
9050  cavetetlist->newindex((void **) &parytet);
9051  *parytet = fliptets[j]; // fliptets[1], fliptets[2].
9052  }
9053  }
9054 
9055  // Star(ab) is reduced. Try to flip the edge [a,b].
9056  nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
9057 
9058  if (nn == 2) {
9059  // The edge has been flipped.
9060  return nn;
9061  } else { // if (nn > 2)
9062  // The edge is not flipped.
9063  if (fc->unflip || (ori == 0)) {
9064  // Undo the previous 2-to-3 flip, i.e., do a 3-to-2 flip to
9065  // transform [e,d] => [a,b,c].
9066  // 'ori == 0' means that the previous flip created a degenerated
9067  // tet. It must be removed.
9068  // Remember that 'abtets[i-1]' is [a,b,e,d]. We can use it to
9069  // find another two tets [e,d,b,c] and [e,d,c,a].
9070  fliptets[0] = abtets[(i-1 + (n-1)) % (n-1)]; // [a,b,e,d]
9071  edestoppoself(fliptets[0]); // [e,d,a,b]
9072  fnext(fliptets[0], fliptets[1]); // [1] is [e,d,b,c]
9073  fnext(fliptets[1], fliptets[2]); // [2] is [e,d,c,a]
9074  // Restore the two original tets in Star(ab).
9075  flip32(fliptets, hullflag, fc);
9076  // Marktest the two restored tets in Star(ab).
9077  for (j = 0; j < 2; j++) {
9078  increaseelemcounter(fliptets[j]);
9079  }
9080  // Expand the array 'abtets', maintain the original order.
9081  for (j = n - 2; j>= i; j--) {
9082  abtets[j + 1] = abtets[j]; // Downshift
9083  }
9084  // Insert the two new tets 'fliptets[0]' [a,b,c,d] and
9085  // 'fliptets[1]' [b,a,c,e] into the (i-1)-th and i-th entries,
9086  // respectively.
9087  esym(fliptets[1], abtets[(i - 1 + n) % n]); // [a,b,e,c]
9088  abtets[i] = fliptets[0]; // [a,b,c,d]
9089  nn++;
9090  if (fc->collectnewtets) {
9091  // Pop two (flipped) tets from the stack.
9092  cavetetlist->objects -= 2;
9093  }
9094  } // if (unflip || (ori == 0))
9095  } // if (nn > 2)
9096 
9097  if (!fc->unflip) {
9098  // The flips are not reversed. The current Star(ab) can not be
9099  // further reduced. Return its current size (# of tets).
9100  return nn;
9101  }
9102  // unflip is set.
9103  // Continue the search for flips.
9104  }
9105  } // if (reducflag)
9106  } // i
9107 
9108  // The Star(ab) is not reduced.
9109  if (reflexlinkedgecount > 0) {
9110  // There are reflex edges in the Link(ab).
9111  if (((b->fliplinklevel < 0) && (level < autofliplinklevel)) ||
9112  ((b->fliplinklevel >= 0) && (level < b->fliplinklevel))) {
9113  // Try to reduce the Star(ab) by flipping a reflex edge in Link(ab).
9114  for (i = 0; i < n; i++) {
9115  // Do not flip this face [a,b,c] if there are two Stars involved.
9116  if ((elemcounter(abtets[i]) > 1) ||
9117  (elemcounter(abtets[(i - 1 + n) % n]) > 1)) {
9118  continue;
9119  }
9120  pc = apex(abtets[i]);
9121  if (pc == dummypoint) {
9122  continue; // [a,b] is a hull edge.
9123  }
9124  pd = apex(abtets[(i + 1) % n]);
9125  pe = apex(abtets[(i - 1 + n) % n]);
9126  if ((pd == dummypoint) || (pe == dummypoint)) {
9127  continue; // [a,b,c] is a hull face.
9128  }
9129 
9130 
9131  edgepivot = 0; // No edge is selected yet.
9132 
9133  // Test if [b,c] is locally convex or flat.
9134  ori = orient3d(pb, pc, pd, pe);
9135  if (ori <= 0) {
9136  // Select the edge [c,b].
9137  enext(abtets[i], flipedge); // [b,c,a,d]
9138  edgepivot = 1;
9139  }
9140  if (!edgepivot) {
9141  // Test if [c,a] is locally convex or flat.
9142  ori = orient3d(pc, pa, pd, pe);
9143  if (ori <= 0) {
9144  // Select the edge [a,c].
9145  eprev(abtets[i], flipedge); // [c,a,b,d].
9146  edgepivot = 2;
9147  }
9148  }
9149 
9150  if (!edgepivot) continue;
9151 
9152  // An edge is selected.
9153  if (checksubsegflag) {
9154  // Do not flip it if it is a segment.
9155  if (issubseg(flipedge)) {
9156  if (fc->collectencsegflag) {
9157  face checkseg, *paryseg;
9158  tsspivot1(flipedge, checkseg);
9159  if (!sinfected(checkseg)) {
9160  // Queue this segment in list.
9161  sinfect(checkseg);
9162  caveencseglist->newindex((void **) &paryseg);
9163  *paryseg = checkseg;
9164  }
9165  }
9166  continue;
9167  }
9168  }
9169 
9170  // Try to flip the selected edge ([c,b] or [a,c]).
9171  esymself(flipedge);
9172  // Count the number of tets at the edge.
9173  n1 = 0;
9174  j = 0; // Sum of the star counters.
9175  spintet = flipedge;
9176  while (1) {
9177  n1++;
9178  j += (elemcounter(spintet));
9179  fnextself(spintet);
9180  if (spintet.tet == flipedge.tet) break;
9181  }
9182  if (n1 < 3) {
9183  // This is only possible when the mesh contains inverted
9184  // elements. Reprot a bug.
9185  terminatetetgen(this, 2);
9186  }
9187  if (j > 2) {
9188  // The Star(flipedge) overlaps other Stars.
9189  continue; // Do not flip this edge.
9190  }
9191 
9192  if ((b->flipstarsize > 0) && (n1 > b->flipstarsize)) {
9193  // The star size exceeds the given limit.
9194  continue; // Do not flip it.
9195  }
9196 
9197  // Allocate spaces for Star(flipedge).
9198  tmpabtets = new triface[n1];
9199  // Form the Star(flipedge).
9200  j = 0;
9201  spintet = flipedge;
9202  while (1) {
9203  tmpabtets[j] = spintet;
9204  // Increase the star counter of this tet.
9205  increaseelemcounter(tmpabtets[j]);
9206  j++;
9207  fnextself(spintet);
9208  if (spintet.tet == flipedge.tet) break;
9209  }
9210 
9211  // Try to flip the selected edge away.
9212  nn = flipnm(tmpabtets, n1, level + 1, edgepivot, fc);
9213 
9214  if (nn == 2) {
9215  // The edge is flipped. Star(ab) is reduced.
9216  // Shrink the array 'abtets', maintain the original order.
9217  if (edgepivot == 1) {
9218  // 'tmpabtets[0]' is [d,a,e,b] => contains [a,b].
9219  spintet = tmpabtets[0]; // [d,a,e,b]
9220  enextself(spintet);
9221  esymself(spintet);
9222  enextself(spintet); // [a,b,e,d]
9223  } else {
9224  // 'tmpabtets[1]' is [b,d,e,a] => contains [a,b].
9225  spintet = tmpabtets[1]; // [b,d,e,a]
9226  eprevself(spintet);
9227  esymself(spintet);
9228  eprevself(spintet); // [a,b,e,d]
9229  } // edgepivot == 2
9230  increaseelemcounter(spintet); // It is in Star(ab).
9231  // Put the new tet at [i-1]-th entry.
9232  abtets[(i - 1 + n) % n] = spintet;
9233  for (j = i; j < n - 1; j++) {
9234  abtets[j] = abtets[j + 1]; // Upshift
9235  }
9236  // Remember the flips in the last entry of the array 'abtets'.
9237  // They can be used to recover the flipped edge.
9238  abtets[n - 1].tet = (tetrahedron *) tmpabtets; // The star(fedge).
9239  abtets[n - 1].ver = 0; // Clear it.
9240  // Use the 1st and 2nd bit to save 'edgepivot' (1 or 2).
9241  abtets[n - 1].ver |= edgepivot;
9242  // Use the 6th bit to signal this n1-to-m1 flip.
9243  abtets[n - 1].ver |= (1 << 5);
9244  // The poisition [i] of this flip is saved from 7th to 19th bit.
9245  abtets[n - 1].ver |= (i << 6);
9246  // The size of the star 'n1' is saved from 20th bit.
9247  abtets[n - 1].ver |= (n1 << 19);
9248 
9249  // Remember the flipped link vertex 'c'. It can be used to recover
9250  // the original edge link of [a,b], and to collect new tets.
9251  tmpabtets[0].tet = (tetrahedron *) pc;
9252  tmpabtets[0].ver = (1 << 5); // Flag it as a vertex handle.
9253 
9254  // Continue to flip the edge [a,b].
9255  nn = flipnm(abtets, n - 1, level, abedgepivot, fc);
9256 
9257  if (nn == 2) {
9258  // The edge has been flipped.
9259  return nn;
9260  } else { // if (nn > 2) {
9261  // The edge is not flipped.
9262  if (fc->unflip) {
9263  // Recover the flipped edge ([c,b] or [a,c]).
9264  // The sequence of flips are saved in 'tmpabtets'.
9265  // abtets[(i-1) % (n-1)] is [a,b,e,d], i.e., the tet created by
9266  // the flipping of edge [c,b] or [a,c].It must still exist in
9267  // Star(ab). It is the start tet to recover the flipped edge.
9268  if (edgepivot == 1) {
9269  // The flip edge is [c,b].
9270  tmpabtets[0] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d]
9271  eprevself(tmpabtets[0]);
9272  esymself(tmpabtets[0]);
9273  eprevself(tmpabtets[0]); // [d,a,e,b]
9274  fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c]
9275  } else {
9276  // The flip edge is [a,c].
9277  tmpabtets[1] = abtets[((i-1)+(n-1))%(n-1)]; // [a,b,e,d]
9278  enextself(tmpabtets[1]);
9279  esymself(tmpabtets[1]);
9280  enextself(tmpabtets[1]); // [b,d,e,a]
9281  fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c]
9282  } // if (edgepivot == 2)
9283 
9284  // Recover the flipped edge ([c,b] or [a,c]).
9285  flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
9286 
9287  // Insert the two recovered tets into Star(ab).
9288  for (j = n - 2; j >= i; j--) {
9289  abtets[j + 1] = abtets[j]; // Downshift
9290  }
9291  if (edgepivot == 1) {
9292  // tmpabtets[0] is [c,b,d,a] ==> contains [a,b]
9293  // tmpabtets[1] is [c,b,a,e] ==> contains [a,b]
9294  // tmpabtets[2] is [c,b,e,d]
9295  fliptets[0] = tmpabtets[1];
9296  enextself(fliptets[0]);
9297  esymself(fliptets[0]); // [a,b,e,c]
9298  fliptets[1] = tmpabtets[0];
9299  esymself(fliptets[1]);
9300  eprevself(fliptets[1]); // [a,b,c,d]
9301  } else {
9302  // tmpabtets[0] is [a,c,d,b] ==> contains [a,b]
9303  // tmpabtets[1] is [a,c,b,e] ==> contains [a,b]
9304  // tmpabtets[2] is [a,c,e,d]
9305  fliptets[0] = tmpabtets[1];
9306  eprevself(fliptets[0]);
9307  esymself(fliptets[0]); // [a,b,e,c]
9308  fliptets[1] = tmpabtets[0];
9309  esymself(fliptets[1]);
9310  enextself(fliptets[1]); // [a,b,c,d]
9311  } // edgepivot == 2
9312  for (j = 0; j < 2; j++) {
9313  increaseelemcounter(fliptets[j]);
9314  }
9315  // Insert the two recovered tets into Star(ab).
9316  abtets[(i - 1 + n) % n] = fliptets[0];
9317  abtets[i] = fliptets[1];
9318  nn++;
9319  // Release the allocated spaces.
9320  delete [] tmpabtets;
9321  } // if (unflip)
9322  } // if (nn > 2)
9323 
9324  if (!fc->unflip) {
9325  // The flips are not reversed. The current Star(ab) can not be
9326  // further reduced. Return its size (# of tets).
9327  return nn;
9328  }
9329  // unflip is set.
9330  // Continue the search for flips.
9331  } else {
9332  // The selected edge is not flipped.
9333  if (!fc->unflip) {
9334  // Release the memory used in this attempted flip.
9335  flipnm_post(tmpabtets, n1, nn, edgepivot, fc);
9336  }
9337  // Decrease the star counters of tets in Star(flipedge).
9338  for (j = 0; j < nn; j++) {
9339  decreaseelemcounter(tmpabtets[j]);
9340  }
9341  // Release the allocated spaces.
9342  delete [] tmpabtets;
9343  }
9344  } // i
9345  } // if (level...)
9346  } // if (reflexlinkedgecount > 0)
9347  } else {
9348  // Check if a 3-to-2 flip is possible.
9349  // Let the three apexes be c, d,and e. Hull tets may be involved. If so,
9350  // we rearrange them such that the vertex e is dummypoint.
9351  hullflag = 0;
9352 
9353  if (apex(abtets[0]) == dummypoint) {
9354  pc = apex(abtets[1]);
9355  pd = apex(abtets[2]);
9356  pe = apex(abtets[0]);
9357  hullflag = 1;
9358  } else if (apex(abtets[1]) == dummypoint) {
9359  pc = apex(abtets[2]);
9360  pd = apex(abtets[0]);
9361  pe = apex(abtets[1]);
9362  hullflag = 2;
9363  } else {
9364  pc = apex(abtets[0]);
9365  pd = apex(abtets[1]);
9366  pe = apex(abtets[2]);
9367  hullflag = (pe == dummypoint) ? 3 : 0;
9368  }
9369 
9370  reducflag = 0;
9371  rejflag = 0;
9372 
9373 
9374  if (hullflag == 0) {
9375  // Make sure that no inverted tet will be created, i.e. the new tets
9376  // [d,c,e,a] and [c,d,e,b] must be valid tets.
9377  ori = orient3d(pd, pc, pe, pa);
9378  if (ori < 0) {
9379  ori = orient3d(pc, pd, pe, pb);
9380  if (ori < 0) {
9381  reducflag = 1;
9382  }
9383  }
9384  } else {
9385  // [a,b] is a hull edge.
9386  // Note: This can happen when it is in the middle of a 4-to-4 flip.
9387  // Note: [a,b] may even be a non-convex hull edge.
9388  if (!nonconvex) {
9389  // The mesh is convex, only do flip if it is a coplanar hull edge.
9390  ori = orient3d(pa, pb, pc, pd);
9391  if (ori == 0) {
9392  reducflag = 1;
9393  }
9394  } else { // nonconvex
9395  reducflag = 1;
9396  }
9397  if (reducflag == 1) {
9398  // [a,b], [a,b,c] and [a,b,d] are on the convex hull.
9399  // Make sure that no inverted tet will be created.
9400  point searchpt = NULL, chkpt;
9401  REAL bigvol = 0.0, ori1, ori2;
9402  // Search an interior vertex which is an apex of edge [c,d].
9403  // In principle, it can be arbitrary interior vertex. To avoid
9404  // numerical issue, we choose the vertex which belongs to a tet
9405  // 't' at edge [c,d] and 't' has the biggest volume.
9406  fliptets[0] = abtets[hullflag % 3]; // [a,b,c,d].
9407  eorgoppoself(fliptets[0]); // [d,c,b,a]
9408  spintet = fliptets[0];
9409  while (1) {
9410  fnextself(spintet);
9411  chkpt = oppo(spintet);
9412  if (chkpt == pb) break;
9413  if ((chkpt != dummypoint) && (apex(spintet) != dummypoint)) {
9414  ori = -orient3d(pd, pc, apex(spintet), chkpt);
9415  if (ori > bigvol) {
9416  bigvol = ori;
9417  searchpt = chkpt;
9418  }
9419  }
9420  }
9421  if (searchpt != NULL) {
9422  // Now valid the configuration.
9423  ori1 = orient3d(pd, pc, searchpt, pa);
9424  ori2 = orient3d(pd, pc, searchpt, pb);
9425  if (ori1 * ori2 >= 0.0) {
9426  reducflag = 0; // Not valid.
9427  } else {
9428  ori1 = orient3d(pa, pb, searchpt, pc);
9429  ori2 = orient3d(pa, pb, searchpt, pd);
9430  if (ori1 * ori2 >= 0.0) {
9431  reducflag = 0; // Not valid.
9432  }
9433  }
9434  } else {
9435  // No valid searchpt is found.
9436  reducflag = 0; // Do not flip it.
9437  }
9438  } // if (reducflag == 1)
9439  } // if (hullflag == 1)
9440 
9441  if (reducflag) {
9442  // A 3-to-2 flip is possible.
9443  if (checksubfaceflag) {
9444  // This edge (must not be a segment) can be flipped ONLY IF it belongs
9445  // to either 0 or 2 subfaces. In the latter case, a 2-to-2 flip in
9446  // the surface mesh will be automatically performed within the
9447  // 3-to-2 flip.
9448  nn = 0;
9449  edgepivot = -1; // Re-use it.
9450  for (j = 0; j < 3; j++) {
9451  if (issubface(abtets[j])) {
9452  nn++; // Found a subface.
9453  } else {
9454  edgepivot = j;
9455  }
9456  }
9457  if (nn == 1) {
9458  // Found only 1 subface containing this edge. This can happen in
9459  // the boundary recovery phase. The neighbor subface is not yet
9460  // recovered. This edge should not be flipped at this moment.
9461  rejflag = 1;
9462  } else if (nn == 2) {
9463  // Found two subfaces. A 2-to-2 flip is possible. Validate it.
9464  // Below we check if the two faces [p,q,a] and [p,q,b] are subfaces.
9465  eorgoppo(abtets[(edgepivot + 1) % 3], spintet); // [q,p,b,a]
9466  if (issubface(spintet)) {
9467  rejflag = 1; // Conflict to a 2-to-2 flip.
9468  } else {
9469  esymself(spintet);
9470  if (issubface(spintet)) {
9471  rejflag = 1; // Conflict to a 2-to-2 flip.
9472  }
9473  }
9474  } else if (nn == 3) {
9475  // Report a bug.
9476  terminatetetgen(this, 2);
9477  }
9478  }
9479  if (!rejflag && fc->checkflipeligibility) {
9480  // Here we must exchange 'a' and 'b'. Since in the check... function,
9481  // we assume the following point sequence, 'a,b,c,d,e', where
9482  // the face [a,b,c] will be flipped and the edge [e,d] will be
9483  // created. The two new tets are [a,b,c,d] and [b,a,c,e].
9484  rejflag = checkflipeligibility(2, pc, pd, pe, pb, pa, level,
9485  abedgepivot, fc);
9486  }
9487  if (!rejflag) {
9488  // Do flip: [a,b] => [c,d,e]
9489  flip32(abtets, hullflag, fc);
9490  if (fc->remove_ndelaunay_edge) {
9491  if (level == 0) {
9492  // It is the desired removing edge. Check if we have improved
9493  // the objective function.
9494  if ((fc->tetprism_vol_sum >= 0.0) ||
9495  (fabs(fc->tetprism_vol_sum) < fc->bak_tetprism_vol)) {
9496  // No improvement! flip back: [c,d,e] => [a,b].
9497  flip23(abtets, hullflag, fc);
9498  // Increase the element counter -- They are in cavity.
9499  for (j = 0; j < 3; j++) {
9500  increaseelemcounter(abtets[j]);
9501  }
9502  return 3;
9503  }
9504  } // if (level == 0)
9505  }
9506  if (fc->collectnewtets) {
9507  // Collect new tets.
9508  if (level == 0) {
9509  // Push the two new tets into stack.
9510  for (j = 0; j < 2; j++) {
9511  cavetetlist->newindex((void **) &parytet);
9512  *parytet = abtets[j];
9513  }
9514  } else {
9515  // Only one of the new tets is collected. The other one is inside
9516  // the reduced edge star. 'abedgepivot' is either '1' or '2'.
9517  cavetetlist->newindex((void **) &parytet);
9518  if (abedgepivot == 1) { // [c,b]
9519  *parytet = abtets[1];
9520  } else {
9521  *parytet = abtets[0];
9522  }
9523  }
9524  } // if (fc->collectnewtets)
9525  return 2;
9526  }
9527  } // if (reducflag)
9528  } // if (n == 3)
9529 
9530  // The current (reduced) Star size.
9531  return n;
9532 }
9533 
9535 // //
9536 // flipnm_post() Post process a n-to-m flip. //
9537 // //
9538 // IMPORTANT: This routine only works when there is no other flip operation //
9539 // is done after flipnm([a,b]) which attempts to remove an edge [a,b]. //
9540 // //
9541 // 'abtets' is an array of 'n' (>= 3) tets which are in the original star of //
9542 // [a,b] before flipnm([a,b]). 'nn' (< n) is the value returned by flipnm. //
9543 // If 'nn == 2', the edge [a,b] has been flipped. 'abtets[0]' and 'abtets[1]'//
9544 // are [c,d,e,b] and [d,c,e,a], i.e., a 2-to-3 flip can recover the edge [a, //
9545 // b] and its initial Star([a,b]). If 'nn >= 3' edge [a,b] still exists in //
9546 // current mesh and 'nn' is the current number of tets in Star([a,b]). //
9547 // //
9548 // Each 'abtets[i]', where nn <= i < n, saves either a 2-to-3 flip or a //
9549 // flipnm([p1,p2]) operation ([p1,p2] != [a,b]) which created the tet //
9550 // 'abtets[t-1]', where '0 <= t <= i'. These information can be used to //
9551 // undo the flips performed in flipnm([a,b]) or to collect new tets created //
9552 // by the flipnm([a,b]) operation. //
9553 // //
9554 // Default, this routine only walks through the flips and frees the spaces //
9555 // allocated during the flipnm([a,b]) operation. //
9556 // //
9557 // If the flag 'fc->unflip' is set, this routine un-does the flips performed //
9558 // in flipnm([a,b]) so that the mesh is returned to its original state //
9559 // before doing the flipnm([a,b]) operation. //
9560 // //
9561 // //
9563 
9564 int tetgenmesh::flipnm_post(triface* abtets, int n, int nn, int abedgepivot,
9565  flipconstraints* fc)
9566 {
9567  triface fliptets[3], flipface;
9568  triface *tmpabtets;
9569  int fliptype;
9570  int edgepivot;
9571  int t, n1;
9572  int i, j;
9573 
9574 
9575  if (nn == 2) {
9576  // The edge [a,b] has been flipped.
9577  // 'abtets[0]' is [c,d,e,b] or [#,#,#,b].
9578  // 'abtets[1]' is [d,c,e,a] or [#,#,#,a].
9579  if (fc->unflip) {
9580  // Do a 2-to-3 flip to recover the edge [a,b]. There may be hull tets.
9581  flip23(abtets, 1, fc);
9582  if (fc->collectnewtets) {
9583  // Pop up new (flipped) tets from the stack.
9584  if (abedgepivot == 0) {
9585  // Two new tets were collected.
9586  cavetetlist->objects -= 2;
9587  } else {
9588  // Only one of the two new tets was collected.
9589  cavetetlist->objects -= 1;
9590  }
9591  }
9592  }
9593  // The initial size of Star(ab) is 3.
9594  nn++;
9595  }
9596 
9597  // Walk through the performed flips.
9598  for (i = nn; i < n; i++) {
9599  // At the beginning of each step 'i', the size of the Star([a,b]) is 'i'.
9600  // At the end of this step, the size of the Star([a,b]) is 'i+1'.
9601  // The sizes of the Link([a,b]) are the same.
9602  fliptype = ((abtets[i].ver >> 4) & 3); // 0, 1, or 2.
9603  if (fliptype == 1) {
9604  // It was a 2-to-3 flip: [a,b,c]->[e,d].
9605  t = (abtets[i].ver >> 6);
9606  if (fc->unflip) {
9607  if (b->verbose > 2) {
9608  printf(" Recover a 2-to-3 flip at f[%d].\n", t);
9609  }
9610  // 'abtets[(t-1)%i]' is the tet [a,b,e,d] in current Star(ab), i.e.,
9611  // it is created by a 2-to-3 flip [a,b,c] => [e,d].
9612  fliptets[0] = abtets[((t - 1) + i) % i]; // [a,b,e,d]
9613  eprevself(fliptets[0]);
9614  esymself(fliptets[0]);
9615  enextself(fliptets[0]); // [e,d,a,b]
9616  fnext(fliptets[0], fliptets[1]); // [e,d,b,c]
9617  fnext(fliptets[1], fliptets[2]); // [e,d,c,a]
9618  // Do a 3-to-2 flip: [e,d] => [a,b,c].
9619  // NOTE: hull tets may be invloved.
9620  flip32(fliptets, 1, fc);
9621  // Expand the array 'abtets', maintain the original order.
9622  // The new array length is (i+1).
9623  for (j = i - 1; j >= t; j--) {
9624  abtets[j + 1] = abtets[j]; // Downshift
9625  }
9626  // The tet abtets[(t-1)%i] is deleted. Insert the two new tets
9627  // 'fliptets[0]' [a,b,c,d] and 'fliptets[1]' [b,a,c,e] into
9628  // the (t-1)-th and t-th entries, respectively.
9629  esym(fliptets[1], abtets[((t-1) + (i+1)) % (i+1)]); // [a,b,e,c]
9630  abtets[t] = fliptets[0]; // [a,b,c,d]
9631  if (fc->collectnewtets) {
9632  // Pop up two (flipped) tets from the stack.
9633  cavetetlist->objects -= 2;
9634  }
9635  }
9636  } else if (fliptype == 2) {
9637  tmpabtets = (triface *) (abtets[i].tet);
9638  n1 = ((abtets[i].ver >> 19) & 8191); // \sum_{i=0^12}{2^i} = 8191
9639  edgepivot = (abtets[i].ver & 3);
9640  t = ((abtets[i].ver >> 6) & 8191);
9641  if (fc->unflip) {
9642  if (b->verbose > 2) {
9643  printf(" Recover a %d-to-m flip at e[%d] of f[%d].\n", n1,
9644  edgepivot, t);
9645  }
9646  // Recover the flipped edge ([c,b] or [a,c]).
9647  // abtets[(t - 1 + i) % i] is [a,b,e,d], i.e., the tet created by
9648  // the flipping of edge [c,b] or [a,c]. It must still exist in
9649  // Star(ab). Use it to recover the flipped edge.
9650  if (edgepivot == 1) {
9651  // The flip edge is [c,b].
9652  tmpabtets[0] = abtets[(t - 1 + i) % i]; // [a,b,e,d]
9653  eprevself(tmpabtets[0]);
9654  esymself(tmpabtets[0]);
9655  eprevself(tmpabtets[0]); // [d,a,e,b]
9656  fsym(tmpabtets[0], tmpabtets[1]); // [a,d,e,c]
9657  } else {
9658  // The flip edge is [a,c].
9659  tmpabtets[1] = abtets[(t - 1 + i) % i]; // [a,b,e,d]
9660  enextself(tmpabtets[1]);
9661  esymself(tmpabtets[1]);
9662  enextself(tmpabtets[1]); // [b,d,e,a]
9663  fsym(tmpabtets[1], tmpabtets[0]); // [d,b,e,c]
9664  } // if (edgepivot == 2)
9665 
9666  // Do a n1-to-m1 flip to recover the flipped edge ([c,b] or [a,c]).
9667  flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
9668 
9669  // Insert the two recovered tets into the original Star(ab).
9670  for (j = i - 1; j >= t; j--) {
9671  abtets[j + 1] = abtets[j]; // Downshift
9672  }
9673  if (edgepivot == 1) {
9674  // tmpabtets[0] is [c,b,d,a] ==> contains [a,b]
9675  // tmpabtets[1] is [c,b,a,e] ==> contains [a,b]
9676  // tmpabtets[2] is [c,b,e,d]
9677  fliptets[0] = tmpabtets[1];
9678  enextself(fliptets[0]);
9679  esymself(fliptets[0]); // [a,b,e,c]
9680  fliptets[1] = tmpabtets[0];
9681  esymself(fliptets[1]);
9682  eprevself(fliptets[1]); // [a,b,c,d]
9683  } else {
9684  // tmpabtets[0] is [a,c,d,b] ==> contains [a,b]
9685  // tmpabtets[1] is [a,c,b,e] ==> contains [a,b]
9686  // tmpabtets[2] is [a,c,e,d]
9687  fliptets[0] = tmpabtets[1];
9688  eprevself(fliptets[0]);
9689  esymself(fliptets[0]); // [a,b,e,c]
9690  fliptets[1] = tmpabtets[0];
9691  esymself(fliptets[1]);
9692  enextself(fliptets[1]); // [a,b,c,d]
9693  } // edgepivot == 2
9694  // Insert the two recovered tets into Star(ab).
9695  abtets[((t-1) + (i+1)) % (i+1)] = fliptets[0];
9696  abtets[t] = fliptets[1];
9697  }
9698  else {
9699  // Only free the spaces.
9700  flipnm_post(tmpabtets, n1, 2, edgepivot, fc);
9701  } // if (!unflip)
9702  if (b->verbose > 2) {
9703  printf(" Release %d spaces at f[%d].\n", n1, i);
9704  }
9705  delete [] tmpabtets;
9706  }
9707  } // i
9708 
9709  return 1;
9710 }
9711 
9713 // //
9714 // insertpoint() Insert a point into current tetrahedralization. //
9715 // //
9716 // The Bowyer-Watson (B-W) algorithm is used to add a new point p into the //
9717 // tetrahedralization T. It first finds a "cavity", denoted as C, in T, C //
9718 // consists of tetrahedra in T that "conflict" with p. If T is a Delaunay //
9719 // tetrahedralization, then all boundary faces (triangles) of C are visible //
9720 // by p, i.e.,C is star-shaped. We can insert p into T by first deleting all //
9721 // tetrahedra in C, then creating new tetrahedra formed by boundary faces of //
9722 // C and p. If T is not a DT, then C may be not star-shaped. It must be //
9723 // modified so that it becomes star-shaped. //
9724 // //
9726 
9727 int tetgenmesh::insertpoint(point insertpt, triface *searchtet, face *splitsh,
9728  face *splitseg, insertvertexflags *ivf)
9729 {
9730  arraypool *swaplist;
9731  triface *cavetet, spintet, neightet, neineitet, *parytet;
9732  triface oldtet, newtet, newneitet;
9733  face checksh, neighsh, *parysh;
9734  face checkseg, *paryseg;
9735  point *pts, pa, pb, pc, *parypt;
9736  enum locateresult loc = OUTSIDE;
9737  REAL sign, ori;
9738  REAL attrib, volume;
9739  bool enqflag;
9740  int t1ver;
9741  int i, j, k, s;
9742 
9743  if (b->verbose > 2) {
9744  printf(" Insert point %d\n", pointmark(insertpt));
9745  }
9746 
9747  // Locate the point.
9748  if (searchtet->tet != NULL) {
9749  loc = (enum locateresult) ivf->iloc;
9750  }
9751 
9752  if (loc == OUTSIDE) {
9753  if (searchtet->tet == NULL) {
9754  if (!b->weighted) {
9755  randomsample(insertpt, searchtet);
9756  } else {
9757  // Weighted DT. There may exist dangling vertex.
9758  *searchtet = recenttet;
9759  }
9760  }
9761  // Locate the point.
9762  loc = locate(insertpt, searchtet);
9763  }
9764 
9765  ivf->iloc = (int) loc; // The return value.
9766 
9767  if (b->weighted) {
9768  if (loc != OUTSIDE) {
9769  // Check if this vertex is regular.
9770  pts = (point *) searchtet->tet;
9771  sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt,
9772  pts[4][3], pts[5][3], pts[6][3], pts[7][3],
9773  insertpt[3]);
9774  if (sign > 0) {
9775  // This new vertex lies above the lower hull. Do not insert it.
9776  ivf->iloc = (int) NONREGULAR;
9777  return 0;
9778  }
9779  }
9780  }
9781 
9782  // Create the initial cavity C(p) which contains all tetrahedra that
9783  // intersect p. It may include 1, 2, or n tetrahedra.
9784  // If p lies on a segment or subface, also create the initial sub-cavity
9785  // sC(p) which contains all subfaces (and segment) which intersect p.
9786 
9787  if (loc == OUTSIDE) {
9788  flip14count++;
9789  // The current hull will be enlarged.
9790  // Add four adjacent boundary tets into list.
9791  for (i = 0; i < 4; i++) {
9792  decode(searchtet->tet[i], neightet);
9793  neightet.ver = epivot[neightet.ver];
9794  cavebdrylist->newindex((void **) &parytet);
9795  *parytet = neightet;
9796  }
9797  infect(*searchtet);
9798  caveoldtetlist->newindex((void **) &parytet);
9799  *parytet = *searchtet;
9800  } else if (loc == INTETRAHEDRON) {
9801  flip14count++;
9802  // Add four adjacent boundary tets into list.
9803  for (i = 0; i < 4; i++) {
9804  decode(searchtet->tet[i], neightet);
9805  neightet.ver = epivot[neightet.ver];
9806  cavebdrylist->newindex((void **) &parytet);
9807  *parytet = neightet;
9808  }
9809  infect(*searchtet);
9810  caveoldtetlist->newindex((void **) &parytet);
9811  *parytet = *searchtet;
9812  } else if (loc == ONFACE) {
9813  flip26count++;
9814  // Add six adjacent boundary tets into list.
9815  j = (searchtet->ver & 3); // The current face number.
9816  for (i = 1; i < 4; i++) {
9817  decode(searchtet->tet[(j + i) % 4], neightet);
9818  neightet.ver = epivot[neightet.ver];
9819  cavebdrylist->newindex((void **) &parytet);
9820  *parytet = neightet;
9821  }
9822  decode(searchtet->tet[j], spintet);
9823  j = (spintet.ver & 3); // The current face number.
9824  for (i = 1; i < 4; i++) {
9825  decode(spintet.tet[(j + i) % 4], neightet);
9826  neightet.ver = epivot[neightet.ver];
9827  cavebdrylist->newindex((void **) &parytet);
9828  *parytet = neightet;
9829  }
9830  infect(spintet);
9831  caveoldtetlist->newindex((void **) &parytet);
9832  *parytet = spintet;
9833  infect(*searchtet);
9834  caveoldtetlist->newindex((void **) &parytet);
9835  *parytet = *searchtet;
9836 
9837  if (ivf->splitbdflag) {
9838  if ((splitsh != NULL) && (splitsh->sh != NULL)) {
9839  // Create the initial sub-cavity sC(p).
9840  smarktest(*splitsh);
9841  caveshlist->newindex((void **) &parysh);
9842  *parysh = *splitsh;
9843  }
9844  } // if (splitbdflag)
9845  } else if (loc == ONEDGE) {
9846  flipn2ncount++;
9847  // Add all adjacent boundary tets into list.
9848  spintet = *searchtet;
9849  while (1) {
9850  eorgoppo(spintet, neightet);
9851  decode(neightet.tet[neightet.ver & 3], neightet);
9852  neightet.ver = epivot[neightet.ver];
9853  cavebdrylist->newindex((void **) &parytet);
9854  *parytet = neightet;
9855  edestoppo(spintet, neightet);
9856  decode(neightet.tet[neightet.ver & 3], neightet);
9857  neightet.ver = epivot[neightet.ver];
9858  cavebdrylist->newindex((void **) &parytet);
9859  *parytet = neightet;
9860  infect(spintet);
9861  caveoldtetlist->newindex((void **) &parytet);
9862  *parytet = spintet;
9863  fnextself(spintet);
9864  if (spintet.tet == searchtet->tet) break;
9865  } // while (1)
9866 
9867  if (ivf->splitbdflag) {
9868  // Create the initial sub-cavity sC(p).
9869  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
9870  smarktest(*splitseg);
9871  splitseg->shver = 0;
9872  spivot(*splitseg, *splitsh);
9873  }
9874  if (splitsh != NULL) {
9875  if (splitsh->sh != NULL) {
9876  // Collect all subfaces share at this edge.
9877  pa = sorg(*splitsh);
9878  neighsh = *splitsh;
9879  while (1) {
9880  // Adjust the origin of its edge to be 'pa'.
9881  if (sorg(neighsh) != pa) {
9882  sesymself(neighsh);
9883  }
9884  // Add this face into list (in B-W cavity).
9885  smarktest(neighsh);
9886  caveshlist->newindex((void **) &parysh);
9887  *parysh = neighsh;
9888  // Add this face into face-at-splitedge list.
9889  cavesegshlist->newindex((void **) &parysh);
9890  *parysh = neighsh;
9891  // Go to the next face at the edge.
9892  spivotself(neighsh);
9893  // Stop if all faces at the edge have been visited.
9894  if (neighsh.sh == splitsh->sh) break;
9895  if (neighsh.sh == NULL) break;
9896  } // while (1)
9897  } // if (not a dangling segment)
9898  }
9899  } // if (splitbdflag)
9900  } else if (loc == INSTAR) {
9901  // We assume that all tets in the star are given in 'caveoldtetlist',
9902  // and they are all infected.
9903  // Collect the boundary faces of the star.
9904  for (i = 0; i < caveoldtetlist->objects; i++) {
9905  cavetet = (triface *) fastlookup(caveoldtetlist, i);
9906  // Check its 4 neighbor tets.
9907  for (j = 0; j < 4; j++) {
9908  decode(cavetet->tet[j], neightet);
9909  if (!infected(neightet)) {
9910  // It's a boundary face.
9911  neightet.ver = epivot[neightet.ver];
9912  cavebdrylist->newindex((void **) &parytet);
9913  *parytet = neightet;
9914  }
9915  }
9916  }
9917  } else if (loc == ONVERTEX) {
9918  // The point already exist. Do nothing and return.
9919  return 0;
9920  }
9921 
9922 
9923  if (ivf->assignmeshsize) {
9924  // Assign mesh size for the new point.
9925  if (bgm != NULL) {
9926  // Interpolate the mesh size from the background mesh.
9927  bgm->decode(point2bgmtet(org(*searchtet)), neightet);
9928  int bgmloc = (int) bgm->scoutpoint(insertpt, &neightet, 0);
9929  if (bgmloc != (int) OUTSIDE) {
9930  insertpt[pointmtrindex] =
9931  bgm->getpointmeshsize(insertpt, &neightet, bgmloc);
9932  setpoint2bgmtet(insertpt, bgm->encode(neightet));
9933  }
9934  } else {
9935  insertpt[pointmtrindex] = getpointmeshsize(insertpt,searchtet,(int)loc);
9936  }
9937  } // if (assignmeshsize)
9938 
9939  if (ivf->bowywat) {
9940  // Update the cavity C(p) using the Bowyer-Watson algorithm.
9941  swaplist = cavetetlist;
9942  cavetetlist = cavebdrylist;
9943  cavebdrylist = swaplist;
9944  for (i = 0; i < cavetetlist->objects; i++) {
9945  // 'cavetet' is an adjacent tet at outside of the cavity.
9946  cavetet = (triface *) fastlookup(cavetetlist, i);
9947  // The tet may be tested and included in the (enlarged) cavity.
9948  if (!infected(*cavetet)) {
9949  // Check for two possible cases for this tet:
9950  // (1) It is a cavity tet, or
9951  // (2) it is a cavity boundary face.
9952  enqflag = false;
9953  if (!marktested(*cavetet)) {
9954  // Do Delaunay (in-sphere) test.
9955  pts = (point *) cavetet->tet;
9956  if (pts[7] != dummypoint) {
9957  // A volume tet. Operate on it.
9958  if (b->weighted) {
9959  sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], insertpt,
9960  pts[4][3], pts[5][3], pts[6][3], pts[7][3],
9961  insertpt[3]);
9962  } else {
9963  sign = insphere_s(pts[4], pts[5], pts[6], pts[7], insertpt);
9964  }
9965  enqflag = (sign < 0.0);
9966  } else {
9967  if (!nonconvex) {
9968  // Test if this hull face is visible by the new point.
9969  ori = orient3d(pts[4], pts[5], pts[6], insertpt);
9970  if (ori < 0) {
9971  // A visible hull face.
9972  // Include it in the cavity. The convex hull will be enlarged.
9973  enqflag = true;
9974  } else if (ori == 0.0) {
9975  // A coplanar hull face. We need to test if this hull face is
9976  // Delaunay or not. We test if the adjacent tet (not faked)
9977  // of this hull face is Delaunay or not.
9978  decode(cavetet->tet[3], neineitet);
9979  if (!infected(neineitet)) {
9980  if (!marktested(neineitet)) {
9981  // Do Delaunay test on this tet.
9982  pts = (point *) neineitet.tet;
9983  if (b->weighted) {
9984  sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt,
9985  pts[4][3], pts[5][3], pts[6][3],
9986  pts[7][3], insertpt[3]);
9987  } else {
9988  sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt);
9989  }
9990  enqflag = (sign < 0.0);
9991  }
9992  } else {
9993  // The adjacent tet is non-Delaunay. The hull face is non-
9994  // Delaunay as well. Include it in the cavity.
9995  enqflag = true;
9996  } // if (!infected(neineitet))
9997  } // if (ori == 0.0)
9998  } else {
9999  // A hull face (must be a subface).
10000  // We FIRST include it in the initial cavity if the adjacent tet
10001  // (not faked) of this hull face is not Delaunay wrt p.
10002  // Whether it belongs to the final cavity will be determined
10003  // during the validation process. 'validflag'.
10004  decode(cavetet->tet[3], neineitet);
10005  if (!infected(neineitet)) {
10006  if (!marktested(neineitet)) {
10007  // Do Delaunay test on this tet.
10008  pts = (point *) neineitet.tet;
10009  if (b->weighted) {
10010  sign = orient4d_s(pts[4],pts[5],pts[6],pts[7], insertpt,
10011  pts[4][3], pts[5][3], pts[6][3],
10012  pts[7][3], insertpt[3]);
10013  } else {
10014  sign = insphere_s(pts[4],pts[5],pts[6],pts[7], insertpt);
10015  }
10016  enqflag = (sign < 0.0);
10017  }
10018  } else {
10019  // The adjacent tet is non-Delaunay. The hull face is non-
10020  // Delaunay as well. Include it in the cavity.
10021  enqflag = true;
10022  } // if (infected(neineitet))
10023  } // if (nonconvex)
10024  } // if (pts[7] != dummypoint)
10025  marktest(*cavetet); // Only test it once.
10026  } // if (!marktested(*cavetet))
10027 
10028  if (enqflag) {
10029  // Found a tet in the cavity. Put other three faces in check list.
10030  k = (cavetet->ver & 3); // The current face number
10031  for (j = 1; j < 4; j++) {
10032  decode(cavetet->tet[(j + k) % 4], neightet);
10033  cavetetlist->newindex((void **) &parytet);
10034  *parytet = neightet;
10035  }
10036  infect(*cavetet);
10037  caveoldtetlist->newindex((void **) &parytet);
10038  *parytet = *cavetet;
10039  } else {
10040  // Found a boundary face of the cavity.
10041  cavetet->ver = epivot[cavetet->ver];
10042  cavebdrylist->newindex((void **) &parytet);
10043  *parytet = *cavetet;
10044  }
10045  } // if (!infected(*cavetet))
10046  } // i
10047 
10048  cavetetlist->restart(); // Clear the working list.
10049  } // if (ivf->bowywat)
10050 
10051  if (checksubsegflag) {
10052  // Collect all segments of C(p).
10053  shellface *ssptr;
10054  for (i = 0; i < caveoldtetlist->objects; i++) {
10055  cavetet = (triface *) fastlookup(caveoldtetlist, i);
10056  if ((ssptr = (shellface*) cavetet->tet[8]) != NULL) {
10057  for (j = 0; j < 6; j++) {
10058  if (ssptr[j]) {
10059  sdecode(ssptr[j], checkseg);
10060  if (!sinfected(checkseg)) {
10061  sinfect(checkseg);
10062  cavetetseglist->newindex((void **) &paryseg);
10063  *paryseg = checkseg;
10064  }
10065  }
10066  } // j
10067  }
10068  } // i
10069  // Uninfect collected segments.
10070  for (i = 0; i < cavetetseglist->objects; i++) {
10071  paryseg = (face *) fastlookup(cavetetseglist, i);
10072  suninfect(*paryseg);
10073  }
10074 
10075  if (ivf->rejflag & 1) {
10076  // Reject this point if it encroaches upon any segment.
10077  face *paryseg1;
10078  for (i = 0; i < cavetetseglist->objects; i++) {
10079  paryseg1 = (face *) fastlookup(cavetetseglist, i);
10080  if (checkseg4encroach((point) paryseg1->sh[3], (point) paryseg1->sh[4],
10081  insertpt)) {
10082  encseglist->newindex((void **) &paryseg);
10083  *paryseg = *paryseg1;
10084  }
10085  } // i
10086  if ((ivf->rejflag & 1) && (encseglist->objects > 0)) {
10087  insertpoint_abort(splitseg, ivf);
10088  ivf->iloc = (int) ENCSEGMENT;
10089  return 0;
10090  }
10091  }
10092  } // if (checksubsegflag)
10093 
10094  if (checksubfaceflag) {
10095  // Collect all subfaces of C(p).
10096  shellface *sptr;
10097  for (i = 0; i < caveoldtetlist->objects; i++) {
10098  cavetet = (triface *) fastlookup(caveoldtetlist, i);
10099  if ((sptr = (shellface*) cavetet->tet[9]) != NULL) {
10100  for (j = 0; j < 4; j++) {
10101  if (sptr[j]) {
10102  sdecode(sptr[j], checksh);
10103  if (!sinfected(checksh)) {
10104  sinfect(checksh);
10105  cavetetshlist->newindex((void **) &parysh);
10106  *parysh = checksh;
10107  }
10108  }
10109  } // j
10110  }
10111  } // i
10112  // Uninfect collected subfaces.
10113  for (i = 0; i < cavetetshlist->objects; i++) {
10114  parysh = (face *) fastlookup(cavetetshlist, i);
10115  suninfect(*parysh);
10116  }
10117 
10118  if (ivf->rejflag & 2) {
10119  REAL rd, cent[3];
10120  badface *bface;
10121  // Reject this point if it encroaches upon any subface.
10122  for (i = 0; i < cavetetshlist->objects; i++) {
10123  parysh = (face *) fastlookup(cavetetshlist, i);
10124  if (checkfac4encroach((point) parysh->sh[3], (point) parysh->sh[4],
10125  (point) parysh->sh[5], insertpt, cent, &rd)) {
10126  encshlist->newindex((void **) &bface);
10127  bface->ss = *parysh;
10128  bface->forg = (point) parysh->sh[3]; // Not a dad one.
10129  for (j = 0; j < 3; j++) bface->cent[j] = cent[j];
10130  bface->key = rd;
10131  }
10132  }
10133  if (encshlist->objects > 0) {
10134  insertpoint_abort(splitseg, ivf);
10135  ivf->iloc = (int) ENCSUBFACE;
10136  return 0;
10137  }
10138  }
10139  } // if (checksubfaceflag)
10140 
10141  if ((ivf->iloc == (int) OUTSIDE) && ivf->refineflag) {
10142  // The vertex lies outside of the domain. And it does not encroach
10143  // upon any boundary segment or subface. Do not insert it.
10144  insertpoint_abort(splitseg, ivf);
10145  return 0;
10146  }
10147 
10148  if (ivf->splitbdflag) {
10149  // The new point locates in surface mesh. Update the sC(p).
10150  // We have already 'smarktested' the subfaces which directly intersect
10151  // with p in 'caveshlist'. From them, we 'smarktest' their neighboring
10152  // subfaces which are included in C(p). Do not across a segment.
10153  for (i = 0; i < caveshlist->objects; i++) {
10154  parysh = (face *) fastlookup(caveshlist, i);
10155  checksh = *parysh;
10156  for (j = 0; j < 3; j++) {
10157  if (!isshsubseg(checksh)) {
10158  spivot(checksh, neighsh);
10159  if (!smarktested(neighsh)) {
10160  stpivot(neighsh, neightet);
10161  if (infected(neightet)) {
10162  fsymself(neightet);
10163  if (infected(neightet)) {
10164  // This subface is inside C(p).
10165  // Check if its diametrical circumsphere encloses 'p'.
10166  // The purpose of this check is to avoid forming invalid
10167  // subcavity in surface mesh.
10168  sign = incircle3d(sorg(neighsh), sdest(neighsh),
10169  sapex(neighsh), insertpt);
10170  if (sign < 0) {
10171  smarktest(neighsh);
10172  caveshlist->newindex((void **) &parysh);
10173  *parysh = neighsh;
10174  }
10175  }
10176  }
10177  }
10178  }
10179  senextself(checksh);
10180  } // j
10181  } // i
10182  } // if (ivf->splitbdflag)
10183 
10184  if (ivf->validflag) {
10185  // Validate C(p) and update it if it is not star-shaped.
10186  int cutcount = 0;
10187 
10188  if (ivf->respectbdflag) {
10189  // The initial cavity may include subfaces which are not on the facets
10190  // being splitting. Find them and make them as boundary of C(p).
10191  // Comment: We have already 'smarktested' the subfaces in sC(p). They
10192  // are completely inside C(p).
10193  for (i = 0; i < cavetetshlist->objects; i++) {
10194  parysh = (face *) fastlookup(cavetetshlist, i);
10195  stpivot(*parysh, neightet);
10196  if (infected(neightet)) {
10197  fsymself(neightet);
10198  if (infected(neightet)) {
10199  // Found a subface inside C(p).
10200  if (!smarktested(*parysh)) {
10201  // It is possible that this face is a boundary subface.
10202  // Check if it is a hull face.
10203  //assert(apex(neightet) != dummypoint);
10204  if (oppo(neightet) != dummypoint) {
10205  fsymself(neightet);
10206  }
10207  if (oppo(neightet) != dummypoint) {
10208  ori = orient3d(org(neightet), dest(neightet), apex(neightet),
10209  insertpt);
10210  if (ori < 0) {
10211  // A visible face, get its neighbor face.
10212  fsymself(neightet);
10213  ori = -ori; // It must be invisible by p.
10214  }
10215  } else {
10216  // A hull tet. It needs to be cut.
10217  ori = 1;
10218  }
10219  // Cut this tet if it is either invisible by or coplanar with p.
10220  if (ori >= 0) {
10221  uninfect(neightet);
10222  unmarktest(neightet);
10223  cutcount++;
10224  neightet.ver = epivot[neightet.ver];
10225  cavebdrylist->newindex((void **) &parytet);
10226  *parytet = neightet;
10227  // Add three new faces to find new boundaries.
10228  for (j = 0; j < 3; j++) {
10229  esym(neightet, neineitet);
10230  neineitet.ver = epivot[neineitet.ver];
10231  cavebdrylist->newindex((void **) &parytet);
10232  *parytet = neineitet;
10233  enextself(neightet);
10234  }
10235  } // if (ori >= 0)
10236  }
10237  }
10238  }
10239  } // i
10240 
10241  // The initial cavity may include segments in its interior. We need to
10242  // Update the cavity so that these segments are on the boundary of
10243  // the cavity.
10244  for (i = 0; i < cavetetseglist->objects; i++) {
10245  paryseg = (face *) fastlookup(cavetetseglist, i);
10246  // Check this segment if it is not a splitting segment.
10247  if (!smarktested(*paryseg)) {
10248  sstpivot1(*paryseg, neightet);
10249  spintet = neightet;
10250  while (1) {
10251  if (!infected(spintet)) break;
10252  fnextself(spintet);
10253  if (spintet.tet == neightet.tet) break;
10254  }
10255  if (infected(spintet)) {
10256  // Find an adjacent tet at this segment such that both faces
10257  // at this segment are not visible by p.
10258  pa = org(neightet);
10259  pb = dest(neightet);
10260  spintet = neightet;
10261  j = 0;
10262  while (1) {
10263  // Check if this face is visible by p.
10264  pc = apex(spintet);
10265  if (pc != dummypoint) {
10266  ori = orient3d(pa, pb, pc, insertpt);
10267  if (ori >= 0) {
10268  // Not visible. Check another face in this tet.
10269  esym(spintet, neineitet);
10270  pc = apex(neineitet);
10271  if (pc != dummypoint) {
10272  ori = orient3d(pb, pa, pc, insertpt);
10273  if (ori >= 0) {
10274  // Not visible. Found this face.
10275  j = 1; // Flag that it is found.
10276  break;
10277  }
10278  }
10279  }
10280  }
10281  fnextself(spintet);
10282  if (spintet.tet == neightet.tet) break;
10283  }
10284  if (j == 0) {
10285  // Not found such a face.
10286  terminatetetgen(this, 2);
10287  }
10288  neightet = spintet;
10289  if (b->verbose > 3) {
10290  printf(" Cut tet (%d, %d, %d, %d)\n",
10291  pointmark(org(neightet)), pointmark(dest(neightet)),
10292  pointmark(apex(neightet)), pointmark(oppo(neightet)));
10293  }
10294  uninfect(neightet);
10295  unmarktest(neightet);
10296  cutcount++;
10297  neightet.ver = epivot[neightet.ver];
10298  cavebdrylist->newindex((void **) &parytet);
10299  *parytet = neightet;
10300  // Add three new faces to find new boundaries.
10301  for (j = 0; j < 3; j++) {
10302  esym(neightet, neineitet);
10303  neineitet.ver = epivot[neineitet.ver];
10304  cavebdrylist->newindex((void **) &parytet);
10305  *parytet = neineitet;
10306  enextself(neightet);
10307  }
10308  }
10309  }
10310  } // i
10311  } // if (ivf->respectbdflag)
10312 
10313  // Update the cavity by removing invisible faces until it is star-shaped.
10314  for (i = 0; i < cavebdrylist->objects; i++) {
10315  cavetet = (triface *) fastlookup(cavebdrylist, i);
10316  // 'cavetet' is an exterior tet adjacent to the cavity.
10317  // Check if its neighbor is inside C(p).
10318  fsym(*cavetet, neightet);
10319  if (infected(neightet)) {
10320  if (apex(*cavetet) != dummypoint) {
10321  // It is a cavity boundary face. Check its visibility.
10322  if (oppo(neightet) != dummypoint) {
10323  // Check if this face is visible by the new point.
10324  if (issubface(neightet)) {
10325  // We should only create a new tet that has a reasonable volume.
10326  // Re-use 'volume' and 'attrib'.
10327  pa = org(*cavetet);
10328  pb = dest(*cavetet);
10329  pc = apex(*cavetet);
10330  volume = orient3dfast(pa, pb, pc, insertpt);
10331  attrib = distance(pa, pb) * distance(pb, pc) * distance(pc, pa);
10332  if ((fabs(volume) / attrib) < b->epsilon) {
10333  ori = 0.0;
10334  } else {
10335  ori = orient3d(pa, pb, pc, insertpt);
10336  }
10337  } else {
10338  ori = orient3d(org(*cavetet), dest(*cavetet), apex(*cavetet),
10339  insertpt);
10340  }
10341  enqflag = (ori > 0);
10342  // Comment: if ori == 0 (coplanar case), we also cut the tet.
10343  } else {
10344  // It is a hull face. And its adjacent tet (at inside of the
10345  // domain) has been cut from the cavity. Cut it as well.
10346  //assert(nonconvex);
10347  enqflag = false;
10348  }
10349  } else {
10350  enqflag = true; // A hull edge.
10351  }
10352  if (enqflag) {
10353  // This face is valid, save it.
10354  cavetetlist->newindex((void **) &parytet);
10355  *parytet = *cavetet;
10356  } else {
10357  uninfect(neightet);
10358  unmarktest(neightet);
10359  cutcount++;
10360  // Add three new faces to find new boundaries.
10361  for (j = 0; j < 3; j++) {
10362  esym(neightet, neineitet);
10363  neineitet.ver = epivot[neineitet.ver];
10364  cavebdrylist->newindex((void **) &parytet);
10365  *parytet = neineitet;
10366  enextself(neightet);
10367  }
10368  // 'cavetet' is not on the cavity boundary anymore.
10369  unmarktest(*cavetet);
10370  }
10371  } else {
10372  // 'cavetet' is not on the cavity boundary anymore.
10373  unmarktest(*cavetet);
10374  }
10375  } // i
10376 
10377  if (cutcount > 0) {
10378  // The cavity has been updated.
10379  // Update the cavity boundary faces.
10380  cavebdrylist->restart();
10381  for (i = 0; i < cavetetlist->objects; i++) {
10382  cavetet = (triface *) fastlookup(cavetetlist, i);
10383  // 'cavetet' was an exterior tet adjacent to the cavity.
10384  fsym(*cavetet, neightet);
10385  if (infected(neightet)) {
10386  // It is a cavity boundary face.
10387  cavebdrylist->newindex((void **) &parytet);
10388  *parytet = *cavetet;
10389  } else {
10390  // Not a cavity boundary face.
10391  unmarktest(*cavetet);
10392  }
10393  }
10394 
10395  // Update the list of old tets.
10396  cavetetlist->restart();
10397  for (i = 0; i < caveoldtetlist->objects; i++) {
10398  cavetet = (triface *) fastlookup(caveoldtetlist, i);
10399  if (infected(*cavetet)) {
10400  cavetetlist->newindex((void **) &parytet);
10401  *parytet = *cavetet;
10402  }
10403  }
10404  // Swap 'cavetetlist' and 'caveoldtetlist'.
10405  swaplist = caveoldtetlist;
10406  caveoldtetlist = cavetetlist;
10407  cavetetlist = swaplist;
10408 
10409  // The cavity should contain at least one tet.
10410  if (caveoldtetlist->objects == 0l) {
10411  insertpoint_abort(splitseg, ivf);
10412  ivf->iloc = (int) BADELEMENT;
10413  return 0;
10414  }
10415 
10416  if (ivf->splitbdflag) {
10417  int cutshcount = 0;
10418  // Update the sub-cavity sC(p).
10419  for (i = 0; i < caveshlist->objects; i++) {
10420  parysh = (face *) fastlookup(caveshlist, i);
10421  if (smarktested(*parysh)) {
10422  enqflag = false;
10423  stpivot(*parysh, neightet);
10424  if (infected(neightet)) {
10425  fsymself(neightet);
10426  if (infected(neightet)) {
10427  enqflag = true;
10428  }
10429  }
10430  if (!enqflag) {
10431  sunmarktest(*parysh);
10432  // Use the last entry of this array to fill this entry.
10433  j = caveshlist->objects - 1;
10434  checksh = * (face *) fastlookup(caveshlist, j);
10435  *parysh = checksh;
10436  cutshcount++;
10437  caveshlist->objects--; // The list is shrinked.
10438  i--;
10439  }
10440  }
10441  }
10442 
10443  if (cutshcount > 0) {
10444  i = 0; // Count the number of invalid subfaces/segments.
10445  // Valid the updated sub-cavity sC(p).
10446  if (loc == ONFACE) {
10447  if ((splitsh != NULL) && (splitsh->sh != NULL)) {
10448  // The to-be split subface should be in sC(p).
10449  if (!smarktested(*splitsh)) i++;
10450  }
10451  } else if (loc == ONEDGE) {
10452  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
10453  // The to-be split segment should be in sC(p).
10454  if (!smarktested(*splitseg)) i++;
10455  }
10456  if ((splitsh != NULL) && (splitsh->sh != NULL)) {
10457  // All subfaces at this edge should be in sC(p).
10458  pa = sorg(*splitsh);
10459  neighsh = *splitsh;
10460  while (1) {
10461  // Adjust the origin of its edge to be 'pa'.
10462  if (sorg(neighsh) != pa) {
10463  sesymself(neighsh);
10464  }
10465  // Add this face into list (in B-W cavity).
10466  if (!smarktested(neighsh)) i++;
10467  // Go to the next face at the edge.
10468  spivotself(neighsh);
10469  // Stop if all faces at the edge have been visited.
10470  if (neighsh.sh == splitsh->sh) break;
10471  if (neighsh.sh == NULL) break;
10472  } // while (1)
10473  }
10474  }
10475 
10476  if (i > 0) {
10477  // The updated sC(p) is invalid. Do not insert this vertex.
10478  insertpoint_abort(splitseg, ivf);
10479  ivf->iloc = (int) BADELEMENT;
10480  return 0;
10481  }
10482  } // if (cutshcount > 0)
10483  } // if (ivf->splitbdflag)
10484  } // if (cutcount > 0)
10485 
10486  } // if (ivf->validflag)
10487 
10488  if (ivf->refineflag) {
10489  // The new point is inserted by Delaunay refinement, i.e., it is the
10490  // circumcenter of a tetrahedron, or a subface, or a segment.
10491  // Do not insert this point if the tetrahedron, or subface, or segment
10492  // is not inside the final cavity.
10493  if (((ivf->refineflag == 1) && !infected(ivf->refinetet)) ||
10494  ((ivf->refineflag == 2) && !smarktested(ivf->refinesh))) {
10495  insertpoint_abort(splitseg, ivf);
10496  ivf->iloc = (int) BADELEMENT;
10497  return 0;
10498  }
10499  } // if (ivf->refineflag)
10500 
10501  if (b->plc && (loc != INSTAR)) {
10502  // Reject the new point if it lies too close to an existing point (b->plc),
10503  // or it lies inside a protecting ball of near vertex (ivf->rejflag & 4).
10504  // Collect the list of vertices of the initial cavity.
10505  if (loc == OUTSIDE) {
10506  pts = (point *) &(searchtet->tet[4]);
10507  for (i = 0; i < 3; i++) {
10508  cavetetvertlist->newindex((void **) &parypt);
10509  *parypt = pts[i];
10510  }
10511  } else if (loc == INTETRAHEDRON) {
10512  pts = (point *) &(searchtet->tet[4]);
10513  for (i = 0; i < 4; i++) {
10514  cavetetvertlist->newindex((void **) &parypt);
10515  *parypt = pts[i];
10516  }
10517  } else if (loc == ONFACE) {
10518  pts = (point *) &(searchtet->tet[4]);
10519  for (i = 0; i < 3; i++) {
10520  cavetetvertlist->newindex((void **) &parypt);
10521  *parypt = pts[i];
10522  }
10523  if (pts[3] != dummypoint) {
10524  cavetetvertlist->newindex((void **) &parypt);
10525  *parypt = pts[3];
10526  }
10527  fsym(*searchtet, spintet);
10528  if (oppo(spintet) != dummypoint) {
10529  cavetetvertlist->newindex((void **) &parypt);
10530  *parypt = oppo(spintet);
10531  }
10532  } else if (loc == ONEDGE) {
10533  spintet = *searchtet;
10534  cavetetvertlist->newindex((void **) &parypt);
10535  *parypt = org(spintet);
10536  cavetetvertlist->newindex((void **) &parypt);
10537  *parypt = dest(spintet);
10538  while (1) {
10539  if (apex(spintet) != dummypoint) {
10540  cavetetvertlist->newindex((void **) &parypt);
10541  *parypt = apex(spintet);
10542  }
10543  fnextself(spintet);
10544  if (spintet.tet == searchtet->tet) break;
10545  }
10546  }
10547 
10548  int rejptflag = (ivf->rejflag & 4);
10549  REAL rd;
10550  pts = NULL;
10551 
10552  for (i = 0; i < cavetetvertlist->objects; i++) {
10553  parypt = (point *) fastlookup(cavetetvertlist, i);
10554  rd = distance(*parypt, insertpt);
10555  // Is the point very close to an existing point?
10556  if (rd < minedgelength) {
10557  pts = parypt;
10558  loc = NEARVERTEX;
10559  break;
10560  }
10561  if (rejptflag) {
10562  // Is the point encroaches upon an existing point?
10563  if (rd < (0.5 * (*parypt)[pointmtrindex])) {
10564  pts = parypt;
10565  loc = ENCVERTEX;
10566  break;
10567  }
10568  }
10569  }
10570  cavetetvertlist->restart(); // Clear the work list.
10571 
10572  if (pts != NULL) {
10573  // The point is either too close to an existing vertex (NEARVERTEX)
10574  // or encroaches upon (inside the protecting ball) of that vertex.
10575  if (loc == NEARVERTEX) {
10576  if (!issteinerpoint(insertpt) && b->nomergevertex) { // -M0/1 option.
10577  // 'insertpt' is an input vertex.
10578  // In this case, we still insert this vertex. Issue a warning.
10579  if (!b->quiet) {
10580  printf("Warning: Two points, %d and %d, are very close.\n",
10581  pointmark(insertpt), pointmark(*pts));
10582  printf(" Creating a very short edge (len = %g) (< %g).\n",
10583  rd, minedgelength);
10584  printf(" You may try a smaller tolerance (-T) (current is %g)\n",
10585  b->epsilon);
10586  printf(" to avoid this warning.\n");
10587  }
10588  } else {
10589  point2tetorg(*pts, *searchtet);
10590  insertpoint_abort(splitseg, ivf);
10591  ivf->iloc = (int) loc;
10592  return 0;
10593  }
10594  } else { // loc == ENCVERTEX
10595  // The point lies inside the protection ball.
10596  point2tetorg(*pts, *searchtet);
10597  insertpoint_abort(splitseg, ivf);
10598  ivf->iloc = (int) loc;
10599  return 0;
10600  }
10601  }
10602  } // if (b->plc && (loc != INSTAR))
10603 
10604  if (b->weighted || ivf->cdtflag || ivf->smlenflag
10605  ) {
10606  // There may be other vertices inside C(p). We need to find them.
10607  // Collect all vertices of C(p).
10608  for (i = 0; i < caveoldtetlist->objects; i++) {
10609  cavetet = (triface *) fastlookup(caveoldtetlist, i);
10610  //assert(infected(*cavetet));
10611  pts = (point *) &(cavetet->tet[4]);
10612  for (j = 0; j < 4; j++) {
10613  if (pts[j] != dummypoint) {
10614  if (!pinfected(pts[j])) {
10615  pinfect(pts[j]);
10616  cavetetvertlist->newindex((void **) &parypt);
10617  *parypt = pts[j];
10618  }
10619  }
10620  } // j
10621  } // i
10622  // Uninfect all collected (cavity) vertices.
10623  for (i = 0; i < cavetetvertlist->objects; i++) {
10624  parypt = (point *) fastlookup(cavetetvertlist, i);
10625  puninfect(*parypt);
10626  }
10627  if (ivf->smlenflag) {
10628  REAL len;
10629  // Get the length of the shortest edge connecting to 'newpt'.
10630  parypt = (point *) fastlookup(cavetetvertlist, 0);
10631  ivf->smlen = distance(*parypt, insertpt);
10632  ivf->parentpt = *parypt;
10633  for (i = 1; i < cavetetvertlist->objects; i++) {
10634  parypt = (point *) fastlookup(cavetetvertlist, i);
10635  len = distance(*parypt, insertpt);
10636  if (len < ivf->smlen) {
10637  ivf->smlen = len;
10638  ivf->parentpt = *parypt;
10639  }
10640  }
10641  }
10642  }
10643 
10644 
10645  if (ivf->cdtflag) {
10646  // Unmark tets.
10647  for (i = 0; i < caveoldtetlist->objects; i++) {
10648  cavetet = (triface *) fastlookup(caveoldtetlist, i);
10649  unmarktest(*cavetet);
10650  }
10651  for (i = 0; i < cavebdrylist->objects; i++) {
10652  cavetet = (triface *) fastlookup(cavebdrylist, i);
10653  unmarktest(*cavetet);
10654  }
10655  // Clean up arrays which are not needed.
10656  cavetetlist->restart();
10657  if (checksubsegflag) {
10658  cavetetseglist->restart();
10659  }
10660  if (checksubfaceflag) {
10661  cavetetshlist->restart();
10662  }
10663  return 1;
10664  }
10665 
10666  // Before re-mesh C(p). Process the segments and subfaces which are on the
10667  // boundary of C(p). Make sure that each such segment or subface is
10668  // connecting to a tet outside C(p). So we can re-connect them to the
10669  // new tets inside the C(p) later.
10670 
10671  if (checksubsegflag) {
10672  for (i = 0; i < cavetetseglist->objects; i++) {
10673  paryseg = (face *) fastlookup(cavetetseglist, i);
10674  // Operate on it if it is not the splitting segment, i.e., in sC(p).
10675  if (!smarktested(*paryseg)) {
10676  // Check if the segment is inside the cavity.
10677  // 'j' counts the num of adjacent tets of this seg.
10678  // 'k' counts the num of adjacent tets which are 'sinfected'.
10679  j = k = 0;
10680  sstpivot1(*paryseg, neightet);
10681  spintet = neightet;
10682  while (1) {
10683  j++;
10684  if (!infected(spintet)) {
10685  neineitet = spintet; // An outer tet. Remember it.
10686  } else {
10687  k++; // An in tet.
10688  }
10689  fnextself(spintet);
10690  if (spintet.tet == neightet.tet) break;
10691  }
10692  // assert(j > 0);
10693  if (k == 0) {
10694  // The segment is not connect to C(p) anymore. Remove it by
10695  // Replacing it by the last entry of this list.
10696  s = cavetetseglist->objects - 1;
10697  checkseg = * (face *) fastlookup(cavetetseglist, s);
10698  *paryseg = checkseg;
10699  cavetetseglist->objects--;
10700  i--;
10701  } else if (k < j) {
10702  // The segment is on the boundary of C(p).
10703  sstbond1(*paryseg, neineitet);
10704  } else { // k == j
10705  // The segment is inside C(p).
10706  if (!ivf->splitbdflag) {
10707  checkseg = *paryseg;
10708  sinfect(checkseg); // Flag it as an interior segment.
10709  caveencseglist->newindex((void **) &paryseg);
10710  *paryseg = checkseg;
10711  } else {
10712  //assert(0); // Not possible.
10713  terminatetetgen(this, 2);
10714  }
10715  }
10716  } else {
10717  // assert(smarktested(*paryseg));
10718  // Flag it as an interior segment. Do not queue it, since it will
10719  // be deleted after the segment splitting.
10720  sinfect(*paryseg);
10721  }
10722  } // i
10723  } // if (checksubsegflag)
10724 
10725  if (checksubfaceflag) {
10726  for (i = 0; i < cavetetshlist->objects; i++) {
10727  parysh = (face *) fastlookup(cavetetshlist, i);
10728  // Operate on it if it is not inside the sub-cavity sC(p).
10729  if (!smarktested(*parysh)) {
10730  // Check if this subface is inside the cavity.
10731  k = 0;
10732  for (j = 0; j < 2; j++) {
10733  stpivot(*parysh, neightet);
10734  if (!infected(neightet)) {
10735  checksh = *parysh; // Remember this side.
10736  } else {
10737  k++;
10738  }
10739  sesymself(*parysh);
10740  }
10741  if (k == 0) {
10742  // The subface is not connected to C(p). Remove it.
10743  s = cavetetshlist->objects - 1;
10744  checksh = * (face *) fastlookup(cavetetshlist, s);
10745  *parysh = checksh;
10746  cavetetshlist->objects--;
10747  i--;
10748  } else if (k == 1) {
10749  // This side is the outer boundary of C(p).
10750  *parysh = checksh;
10751  } else { // k == 2
10752  if (!ivf->splitbdflag) {
10753  checksh = *parysh;
10754  sinfect(checksh); // Flag it.
10755  caveencshlist->newindex((void **) &parysh);
10756  *parysh = checksh;
10757  } else {
10758  //assert(0); // Not possible.
10759  terminatetetgen(this, 2);
10760  }
10761  }
10762  } else {
10763  // assert(smarktested(*parysh));
10764  // Flag it as an interior subface. Do not queue it. It will be
10765  // deleted after the facet point insertion.
10766  sinfect(*parysh);
10767  }
10768  } // i
10769  } // if (checksubfaceflag)
10770 
10771  // Create new tetrahedra to fill the cavity.
10772 
10773  for (i = 0; i < cavebdrylist->objects; i++) {
10774  cavetet = (triface *) fastlookup(cavebdrylist, i);
10775  neightet = *cavetet;
10776  unmarktest(neightet); // Unmark it.
10777  // Get the oldtet (inside the cavity).
10778  fsym(neightet, oldtet);
10779  if (apex(neightet) != dummypoint) {
10780  // Create a new tet in the cavity.
10781  maketetrahedron(&newtet);
10782  setorg(newtet, dest(neightet));
10783  setdest(newtet, org(neightet));
10784  setapex(newtet, apex(neightet));
10785  setoppo(newtet, insertpt);
10786  } else {
10787  // Create a new hull tet.
10788  hullsize++;
10789  maketetrahedron(&newtet);
10790  setorg(newtet, org(neightet));
10791  setdest(newtet, dest(neightet));
10792  setapex(newtet, insertpt);
10793  setoppo(newtet, dummypoint); // It must opposite to face 3.
10794  // Adjust back to the cavity bounday face.
10795  esymself(newtet);
10796  }
10797  // The new tet inherits attribtes from the old tet.
10798  for (j = 0; j < numelemattrib; j++) {
10799  attrib = elemattribute(oldtet.tet, j);
10800  setelemattribute(newtet.tet, j, attrib);
10801  }
10802  if (b->varvolume) {
10803  volume = volumebound(oldtet.tet);
10804  setvolumebound(newtet.tet, volume);
10805  }
10806  // Connect newtet <==> neightet, this also disconnect the old bond.
10807  bond(newtet, neightet);
10808  // oldtet still connects to neightet.
10809  *cavetet = oldtet; // *cavetet = newtet;
10810  } // i
10811 
10812  // Set a handle for speeding point location.
10813  recenttet = newtet;
10814  //setpoint2tet(insertpt, encode(newtet));
10815  setpoint2tet(insertpt, (tetrahedron) (newtet.tet));
10816 
10817  // Re-use this list to save new interior cavity faces.
10818  cavetetlist->restart();
10819 
10820  // Connect adjacent new tetrahedra together.
10821  for (i = 0; i < cavebdrylist->objects; i++) {
10822  cavetet = (triface *) fastlookup(cavebdrylist, i);
10823  // cavtet is an oldtet, get the newtet at this face.
10824  oldtet = *cavetet;
10825  fsym(oldtet, neightet);
10826  fsym(neightet, newtet);
10827  // Comment: oldtet and newtet must be at the same directed edge.
10828  // Connect the three other faces of this newtet.
10829  for (j = 0; j < 3; j++) {
10830  esym(newtet, neightet); // Go to the face.
10831  if (neightet.tet[neightet.ver & 3] == NULL) {
10832  // Find the adjacent face of this newtet.
10833  spintet = oldtet;
10834  while (1) {
10835  fnextself(spintet);
10836  if (!infected(spintet)) break;
10837  }
10838  fsym(spintet, newneitet);
10839  esymself(newneitet);
10840  bond(neightet, newneitet);
10841  if (ivf->lawson > 1) {
10842  cavetetlist->newindex((void **) &parytet);
10843  *parytet = neightet;
10844  }
10845  }
10846  //setpoint2tet(org(newtet), encode(newtet));
10847  setpoint2tet(org(newtet), (tetrahedron) (newtet.tet));
10848  enextself(newtet);
10849  enextself(oldtet);
10850  }
10851  *cavetet = newtet; // Save the new tet.
10852  } // i
10853 
10854  if (checksubfaceflag) {
10855  // Connect subfaces on the boundary of the cavity to the new tets.
10856  for (i = 0; i < cavetetshlist->objects; i++) {
10857  parysh = (face *) fastlookup(cavetetshlist, i);
10858  // Connect it if it is not a missing subface.
10859  if (!sinfected(*parysh)) {
10860  stpivot(*parysh, neightet);
10861  fsym(neightet, spintet);
10862  sesymself(*parysh);
10863  tsbond(spintet, *parysh);
10864  }
10865  }
10866  }
10867 
10868  if (checksubsegflag) {
10869  // Connect segments on the boundary of the cavity to the new tets.
10870  for (i = 0; i < cavetetseglist->objects; i++) {
10871  paryseg = (face *) fastlookup(cavetetseglist, i);
10872  // Connect it if it is not a missing segment.
10873  if (!sinfected(*paryseg)) {
10874  sstpivot1(*paryseg, neightet);
10875  spintet = neightet;
10876  while (1) {
10877  tssbond1(spintet, *paryseg);
10878  fnextself(spintet);
10879  if (spintet.tet == neightet.tet) break;
10880  }
10881  }
10882  }
10883  }
10884 
10885  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
10886  ((splitseg != NULL) && (splitseg->sh != NULL))) {
10887  // Split a subface or a segment.
10888  sinsertvertex(insertpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat, 0);
10889  }
10890 
10891  if (checksubfaceflag) {
10892  if (ivf->splitbdflag) {
10893  // Recover new subfaces in C(p).
10894  for (i = 0; i < caveshbdlist->objects; i++) {
10895  // Get an old subface at edge [a, b].
10896  parysh = (face *) fastlookup(caveshbdlist, i);
10897  spivot(*parysh, checksh); // The new subface [a, b, p].
10898  // Do not recover a deleted new face (degenerated).
10899  if (checksh.sh[3] != NULL) {
10900  // Note that the old subface still connects to adjacent old tets
10901  // of C(p), which still connect to the tets outside C(p).
10902  stpivot(*parysh, neightet);
10903  // Find the adjacent tet containing the edge [a,b] outside C(p).
10904  spintet = neightet;
10905  while (1) {
10906  fnextself(spintet);
10907  if (!infected(spintet)) break;
10908  }
10909  // The adjacent tet connects to a new tet in C(p).
10910  fsym(spintet, neightet);
10911  // Find the tet containing the face [a, b, p].
10912  spintet = neightet;
10913  while (1) {
10914  fnextself(spintet);
10915  if (apex(spintet) == insertpt) break;
10916  }
10917  // Adjust the edge direction in spintet and checksh.
10918  if (sorg(checksh) != org(spintet)) {
10919  sesymself(checksh);
10920  }
10921  // Connect the subface to two adjacent tets.
10922  tsbond(spintet, checksh);
10923  fsymself(spintet);
10924  sesymself(checksh);
10925  tsbond(spintet, checksh);
10926  } // if (checksh.sh[3] != NULL)
10927  }
10928  } else {
10929  // The Boundary recovery phase.
10930  // Put all new subfaces into stack for recovery.
10931  for (i = 0; i < caveshbdlist->objects; i++) {
10932  // Get an old subface at edge [a, b].
10933  parysh = (face *) fastlookup(caveshbdlist, i);
10934  spivot(*parysh, checksh); // The new subface [a, b, p].
10935  // Do not recover a deleted new face (degenerated).
10936  if (checksh.sh[3] != NULL) {
10937  subfacstack->newindex((void **) &parysh);
10938  *parysh = checksh;
10939  }
10940  }
10941  // Put all interior subfaces into stack for recovery.
10942  for (i = 0; i < caveencshlist->objects; i++) {
10943  parysh = (face *) fastlookup(caveencshlist, i);
10944  // Some subfaces inside C(p) might be split in sinsertvertex().
10945  // Only queue those faces which are not split.
10946  if (!smarktested(*parysh)) {
10947  checksh = *parysh;
10948  suninfect(checksh);
10949  stdissolve(checksh); // Detach connections to old tets.
10950  subfacstack->newindex((void **) &parysh);
10951  *parysh = checksh;
10952  }
10953  }
10954  }
10955  } // if (checksubfaceflag)
10956 
10957  if (checksubsegflag) {
10958  if (ivf->splitbdflag) {
10959  if (splitseg != NULL) {
10960  // Recover the two new subsegments in C(p).
10961  for (i = 0; i < cavesegshlist->objects; i++) {
10962  paryseg = (face *) fastlookup(cavesegshlist, i);
10963  // Insert this subsegment into C(p).
10964  checkseg = *paryseg;
10965  // Get the adjacent new subface.
10966  checkseg.shver = 0;
10967  spivot(checkseg, checksh);
10968  if (checksh.sh != NULL) {
10969  // Get the adjacent new tetrahedron.
10970  stpivot(checksh, neightet);
10971  } else {
10972  // It's a dangling segment.
10973  point2tetorg(sorg(checkseg), neightet);
10974  finddirection(&neightet, sdest(checkseg));
10975  }
10976  sstbond1(checkseg, neightet);
10977  spintet = neightet;
10978  while (1) {
10979  tssbond1(spintet, checkseg);
10980  fnextself(spintet);
10981  if (spintet.tet == neightet.tet) break;
10982  }
10983  }
10984  } // if (splitseg != NULL)
10985  } else {
10986  // The Boundary Recovery Phase.
10987  // Queue missing segments in C(p) for recovery.
10988  if (splitseg != NULL) {
10989  // Queue two new subsegments in C(p) for recovery.
10990  for (i = 0; i < cavesegshlist->objects; i++) {
10991  paryseg = (face *) fastlookup(cavesegshlist, i);
10992  checkseg = *paryseg;
10993  //sstdissolve1(checkseg); // It has not been connected yet.
10994  s = randomnation(subsegstack->objects + 1);
10995  subsegstack->newindex((void **) &paryseg);
10996  *paryseg = * (face *) fastlookup(subsegstack, s);
10997  paryseg = (face *) fastlookup(subsegstack, s);
10998  *paryseg = checkseg;
10999  }
11000  } // if (splitseg != NULL)
11001  for (i = 0; i < caveencseglist->objects; i++) {
11002  paryseg = (face *) fastlookup(caveencseglist, i);
11003  if (!smarktested(*paryseg)) { // It may be split.
11004  checkseg = *paryseg;
11005  suninfect(checkseg);
11006  sstdissolve1(checkseg); // Detach connections to old tets.
11007  s = randomnation(subsegstack->objects + 1);
11008  subsegstack->newindex((void **) &paryseg);
11009  *paryseg = * (face *) fastlookup(subsegstack, s);
11010  paryseg = (face *) fastlookup(subsegstack, s);
11011  *paryseg = checkseg;
11012  }
11013  }
11014  }
11015  } // if (checksubsegflag)
11016 
11017  if (b->weighted
11018  ) {
11019  // Some vertices may be completed inside the cavity. They must be
11020  // detected and added to recovering list.
11021  // Since every "live" vertex must contain a pointer to a non-dead
11022  // tetrahedron, we can check for each vertex this pointer.
11023  for (i = 0; i < cavetetvertlist->objects; i++) {
11024  pts = (point *) fastlookup(cavetetvertlist, i);
11025  decode(point2tet(*pts), *searchtet);
11026  if (infected(*searchtet)) {
11027  if (b->weighted) {
11028  if (b->verbose > 1) {
11029  printf(" Point #%d is non-regular after the insertion of #%d.\n",
11030  pointmark(*pts), pointmark(insertpt));
11031  }
11032  setpointtype(*pts, NREGULARVERTEX);
11033  nonregularcount++;
11034  }
11035  }
11036  }
11037  }
11038 
11039  if (ivf->chkencflag & 1) {
11040  // Queue all segment outside C(p).
11041  for (i = 0; i < cavetetseglist->objects; i++) {
11042  paryseg = (face *) fastlookup(cavetetseglist, i);
11043  // Skip if it is the split segment.
11044  if (!sinfected(*paryseg)) {
11045  enqueuesubface(badsubsegs, paryseg);
11046  }
11047  }
11048  if (splitseg != NULL) {
11049  // Queue the two new subsegments inside C(p).
11050  for (i = 0; i < cavesegshlist->objects; i++) {
11051  paryseg = (face *) fastlookup(cavesegshlist, i);
11052  enqueuesubface(badsubsegs, paryseg);
11053  }
11054  }
11055  } // if (chkencflag & 1)
11056 
11057  if (ivf->chkencflag & 2) {
11058  // Queue all subfaces outside C(p).
11059  for (i = 0; i < cavetetshlist->objects; i++) {
11060  parysh = (face *) fastlookup(cavetetshlist, i);
11061  // Skip if it is a split subface.
11062  if (!sinfected(*parysh)) {
11063  enqueuesubface(badsubfacs, parysh);
11064  }
11065  }
11066  // Queue all new subfaces inside C(p).
11067  for (i = 0; i < caveshbdlist->objects; i++) {
11068  // Get an old subface at edge [a, b].
11069  parysh = (face *) fastlookup(caveshbdlist, i);
11070  spivot(*parysh, checksh); // checksh is a new subface [a, b, p].
11071  // Do not recover a deleted new face (degenerated).
11072  if (checksh.sh[3] != NULL) {
11073  enqueuesubface(badsubfacs, &checksh);
11074  }
11075  }
11076  } // if (chkencflag & 2)
11077 
11078  if (ivf->chkencflag & 4) {
11079  // Queue all new tetrahedra in C(p).
11080  for (i = 0; i < cavebdrylist->objects; i++) {
11081  cavetet = (triface *) fastlookup(cavebdrylist, i);
11082  enqueuetetrahedron(cavetet);
11083  }
11084  }
11085 
11086  // C(p) is re-meshed successfully.
11087 
11088  // Delete the old tets in C(p).
11089  for (i = 0; i < caveoldtetlist->objects; i++) {
11090  searchtet = (triface *) fastlookup(caveoldtetlist, i);
11091  if (ishulltet(*searchtet)) {
11092  hullsize--;
11093  }
11094  tetrahedrondealloc(searchtet->tet);
11095  }
11096 
11097  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
11098  ((splitseg != NULL) && (splitseg->sh != NULL))) {
11099  // Delete the old subfaces in sC(p).
11100  for (i = 0; i < caveshlist->objects; i++) {
11101  parysh = (face *) fastlookup(caveshlist, i);
11102  if (checksubfaceflag) {//if (bowywat == 2) {
11103  // It is possible that this subface still connects to adjacent
11104  // tets which are not in C(p). If so, clear connections in the
11105  // adjacent tets at this subface.
11106  stpivot(*parysh, neightet);
11107  if (neightet.tet != NULL) {
11108  if (neightet.tet[4] != NULL) {
11109  // Found an adjacent tet. It must be not in C(p).
11110  tsdissolve(neightet);
11111  fsymself(neightet);
11112  tsdissolve(neightet);
11113  }
11114  }
11115  }
11116  shellfacedealloc(subfaces, parysh->sh);
11117  }
11118  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
11119  // Delete the old segment in sC(p).
11120  shellfacedealloc(subsegs, splitseg->sh);
11121  }
11122  }
11123 
11124  if (ivf->lawson) {
11125  for (i = 0; i < cavebdrylist->objects; i++) {
11126  searchtet = (triface *) fastlookup(cavebdrylist, i);
11127  flippush(flipstack, searchtet);
11128  }
11129  if (ivf->lawson > 1) {
11130  for (i = 0; i < cavetetlist->objects; i++) {
11131  searchtet = (triface *) fastlookup(cavetetlist, i);
11132  flippush(flipstack, searchtet);
11133  }
11134  }
11135  }
11136 
11137 
11138  // Clean the working lists.
11139 
11140  caveoldtetlist->restart();
11141  cavebdrylist->restart();
11142  cavetetlist->restart();
11143 
11144  if (checksubsegflag) {
11145  cavetetseglist->restart();
11146  caveencseglist->restart();
11147  }
11148 
11149  if (checksubfaceflag) {
11150  cavetetshlist->restart();
11151  caveencshlist->restart();
11152  }
11153 
11154  if (b->weighted || ivf->smlenflag
11155  ) {
11156  cavetetvertlist->restart();
11157  }
11158 
11159  if (((splitsh != NULL) && (splitsh->sh != NULL)) ||
11160  ((splitseg != NULL) && (splitseg->sh != NULL))) {
11161  caveshlist->restart();
11162  caveshbdlist->restart();
11163  cavesegshlist->restart();
11164  }
11165 
11166  return 1; // Point is inserted.
11167 }
11168 
11170 // //
11171 // insertpoint_abort() Abort the insertion of a new vertex. //
11172 // //
11173 // The cavity will be restored. All working lists are cleared. //
11174 // //
11176 
11177 void tetgenmesh::insertpoint_abort(face *splitseg, insertvertexflags *ivf)
11178 {
11179  triface *cavetet;
11180  face *parysh;
11181  int i;
11182 
11183  for (i = 0; i < caveoldtetlist->objects; i++) {
11184  cavetet = (triface *) fastlookup(caveoldtetlist, i);
11185  uninfect(*cavetet);
11186  unmarktest(*cavetet);
11187  }
11188  for (i = 0; i < cavebdrylist->objects; i++) {
11189  cavetet = (triface *) fastlookup(cavebdrylist, i);
11190  unmarktest(*cavetet);
11191  }
11192  cavetetlist->restart();
11193  cavebdrylist->restart();
11194  caveoldtetlist->restart();
11195  cavetetseglist->restart();
11196  cavetetshlist->restart();
11197  if (ivf->splitbdflag) {
11198  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
11199  sunmarktest(*splitseg);
11200  }
11201  for (i = 0; i < caveshlist->objects; i++) {
11202  parysh = (face *) fastlookup(caveshlist, i);
11203  sunmarktest(*parysh);
11204  }
11205  caveshlist->restart();
11206  cavesegshlist->restart();
11207  }
11208 }
11209 
11213 
11217 
11219 // //
11220 // transfernodes() Read the vertices from the input (tetgenio). //
11221 // //
11222 // Transferring all points from input ('in->pointlist') to TetGen's 'points'.//
11223 // All points are indexed (the first point index is 'in->firstnumber'). Each //
11224 // point's type is initialized as UNUSEDVERTEX. The bounding box (xmax, xmin,//
11225 // ...) and the diameter (longest) of the point set are calculated. //
11226 // //
11228 
11229 void tetgenmesh::transfernodes()
11230 {
11231  point pointloop;
11232  REAL x, y, z, w;
11233  int coordindex;
11234  int attribindex;
11235  int mtrindex;
11236  int i, j;
11237 
11238  // Read the points.
11239  coordindex = 0;
11240  attribindex = 0;
11241  mtrindex = 0;
11242  for (i = 0; i < in->numberofpoints; i++) {
11243  makepoint(&pointloop, UNUSEDVERTEX);
11244  // Read the point coordinates.
11245  x = pointloop[0] = in->pointlist[coordindex++];
11246  y = pointloop[1] = in->pointlist[coordindex++];
11247  z = pointloop[2] = in->pointlist[coordindex++];
11248  // Read the point attributes. (Including point weights.)
11249  for (j = 0; j < in->numberofpointattributes; j++) {
11250  pointloop[3 + j] = in->pointattributelist[attribindex++];
11251  }
11252  // Read the point metric tensor.
11253  for (j = 0; j < in->numberofpointmtrs; j++) {
11254  pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++];
11255  }
11256  if (b->weighted) { // -w option
11257  if (in->numberofpointattributes > 0) {
11258  // The first point attribute is its weight.
11259  //w = in->pointattributelist[in->numberofpointattributes * i];
11260  w = pointloop[3];
11261  } else {
11262  // No given weight available. Default choose the maximum
11263  // absolute value among its coordinates.
11264  w = fabs(x);
11265  if (w < fabs(y)) w = fabs(y);
11266  if (w < fabs(z)) w = fabs(z);
11267  }
11268  if (b->weighted_param == 0) {
11269  pointloop[3] = x * x + y * y + z * z - w; // Weighted DT.
11270  } else { // -w1 option
11271  pointloop[3] = w; // Regular tetrahedralization.
11272  }
11273  }
11274  // Determine the smallest and largest x, y and z coordinates.
11275  if (i == 0) {
11276  xmin = xmax = x;
11277  ymin = ymax = y;
11278  zmin = zmax = z;
11279  } else {
11280  xmin = (x < xmin) ? x : xmin;
11281  xmax = (x > xmax) ? x : xmax;
11282  ymin = (y < ymin) ? y : ymin;
11283  ymax = (y > ymax) ? y : ymax;
11284  zmin = (z < zmin) ? z : zmin;
11285  zmax = (z > zmax) ? z : zmax;
11286  }
11287  if (b->psc) {
11288  // Read the geometry parameters.
11289  setpointgeomuv(pointloop, 0, in->pointparamlist[i].uv[0]);
11290  setpointgeomuv(pointloop, 1, in->pointparamlist[i].uv[1]);
11291  setpointgeomtag(pointloop, in->pointparamlist[i].tag);
11292  if (in->pointparamlist[i].type == 0) {
11293  setpointtype(pointloop, RIDGEVERTEX);
11294  } else if (in->pointparamlist[i].type == 1) {
11295  setpointtype(pointloop, FREESEGVERTEX);
11296  } else if (in->pointparamlist[i].type == 2) {
11297  setpointtype(pointloop, FREEFACETVERTEX);
11298  } else if (in->pointparamlist[i].type == 3) {
11299  setpointtype(pointloop, FREEVOLVERTEX);
11300  }
11301  }
11302  }
11303 
11304  // 'longest' is the largest possible edge length formed by input vertices.
11305  x = xmax - xmin;
11306  y = ymax - ymin;
11307  z = zmax - zmin;
11308  longest = sqrt(x * x + y * y + z * z);
11309  if (longest == 0.0) {
11310  printf("Error: The point set is trivial.\n");
11311  terminatetetgen(this, 10);
11312  }
11313  // Two identical points are distinguished by 'minedgelength'.
11314  minedgelength = longest * b->epsilon;
11315 }
11316 
11318 // //
11319 // hilbert_init() Initialize the Gray code permutation table. //
11320 // //
11321 // The table 'transgc' has 8 x 3 x 8 entries. It contains all possible Gray //
11322 // code sequences traveled by the 1st order Hilbert curve in 3 dimensions. //
11323 // The first column is the Gray code of the entry point of the curve, and //
11324 // the second column is the direction (0, 1, or 2, 0 means the x-axis) where //
11325 // the exit point of curve lies. //
11326 // //
11327 // The table 'tsb1mod3' contains the numbers of trailing set '1' bits of the //
11328 // indices from 0 to 7, modulo by '3'. The code for generating this table is //
11329 // from: http://graphics.stanford.edu/~seander/bithacks.html. //
11330 // //
11332 
11333 void tetgenmesh::hilbert_init(int n)
11334 {
11335  int gc[8], N, mask, travel_bit;
11336  int e, d, f, k, g;
11337  int v, c;
11338  int i;
11339 
11340  N = (n == 2) ? 4 : 8;
11341  mask = (n == 2) ? 3 : 7;
11342 
11343  // Generate the Gray code sequence.
11344  for (i = 0; i < N; i++) {
11345  gc[i] = i ^ (i >> 1);
11346  }
11347 
11348  for (e = 0; e < N; e++) {
11349  for (d = 0; d < n; d++) {
11350  // Calculate the end point (f).
11351  f = e ^ (1 << d); // Toggle the d-th bit of 'e'.
11352  // travel_bit = 2**p, the bit we want to travel.
11353  travel_bit = e ^ f;
11354  for (i = 0; i < N; i++) {
11355  // // Rotate gc[i] left by (p + 1) % n bits.
11356  k = gc[i] * (travel_bit * 2);
11357  g = ((k | (k / N)) & mask);
11358  // Calculate the permuted Gray code by xor with the start point (e).
11359  transgc[e][d][i] = (g ^ e);
11360  }
11361  } // d
11362  } // e
11363 
11364  // Count the consecutive '1' bits (trailing) on the right.
11365  tsb1mod3[0] = 0;
11366  for (i = 1; i < N; i++) {
11367  v = ~i; // Count the 0s.
11368  v = (v ^ (v - 1)) >> 1; // Set v's trailing 0s to 1s and zero rest
11369  for (c = 0; v; c++) {
11370  v >>= 1;
11371  }
11372  tsb1mod3[i] = c % n;
11373  }
11374 }
11375 
11377 // //
11378 // hilbert_sort3() Sort points using the 3d Hilbert curve. //
11379 // //
11381 
11382 int tetgenmesh::hilbert_split(point* vertexarray,int arraysize,int gc0,int gc1,
11383  REAL bxmin, REAL bxmax, REAL bymin, REAL bymax,
11384  REAL bzmin, REAL bzmax)
11385 {
11386  point swapvert;
11387  int axis, d;
11388  REAL split;
11389  int i, j;
11390 
11391 
11392  // Find the current splitting axis. 'axis' is a value 0, or 1, or 2, which
11393  // correspoding to x-, or y- or z-axis.
11394  axis = (gc0 ^ gc1) >> 1;
11395 
11396  // Calulate the split position along the axis.
11397  if (axis == 0) {
11398  split = 0.5 * (bxmin + bxmax);
11399  } else if (axis == 1) {
11400  split = 0.5 * (bymin + bymax);
11401  } else { // == 2
11402  split = 0.5 * (bzmin + bzmax);
11403  }
11404 
11405  // Find the direction (+1 or -1) of the axis. If 'd' is +1, the direction
11406  // of the axis is to the positive of the axis, otherwise, it is -1.
11407  d = ((gc0 & (1<<axis)) == 0) ? 1 : -1;
11408 
11409 
11410  // Partition the vertices into left- and right-arrays such that left points
11411  // have Hilbert indices lower than the right points.
11412  i = 0;
11413  j = arraysize - 1;
11414 
11415  // Partition the vertices into left- and right-arrays.
11416  if (d > 0) {
11417  do {
11418  for (; i < arraysize; i++) {
11419  if (vertexarray[i][axis] >= split) break;
11420  }
11421  for (; j >= 0; j--) {
11422  if (vertexarray[j][axis] < split) break;
11423  }
11424  // Is the partition finished?
11425  if (i == (j + 1)) break;
11426  // Swap i-th and j-th vertices.
11427  swapvert = vertexarray[i];
11428  vertexarray[i] = vertexarray[j];
11429  vertexarray[j] = swapvert;
11430  // Continue patitioning the array;
11431  } while (true);
11432  } else {
11433  do {
11434  for (; i < arraysize; i++) {
11435  if (vertexarray[i][axis] <= split) break;
11436  }
11437  for (; j >= 0; j--) {
11438  if (vertexarray[j][axis] > split) break;
11439  }
11440  // Is the partition finished?
11441  if (i == (j + 1)) break;
11442  // Swap i-th and j-th vertices.
11443  swapvert = vertexarray[i];
11444  vertexarray[i] = vertexarray[j];
11445  vertexarray[j] = swapvert;
11446  // Continue patitioning the array;
11447  } while (true);
11448  }
11449 
11450  return i;
11451 }
11452 
11453 void tetgenmesh::hilbert_sort3(point* vertexarray, int arraysize, int e, int d,
11454  REAL bxmin, REAL bxmax, REAL bymin, REAL bymax,
11455  REAL bzmin, REAL bzmax, int depth)
11456 {
11457  REAL x1, x2, y1, y2, z1, z2;
11458  int p[9], w, e_w, d_w, k, ei, di;
11459  int n = 3, mask = 7;
11460 
11461  p[0] = 0;
11462  p[8] = arraysize;
11463 
11464  // Sort the points according to the 1st order Hilbert curve in 3d.
11465  p[4] = hilbert_split(vertexarray, p[8], transgc[e][d][3], transgc[e][d][4],
11466  bxmin, bxmax, bymin, bymax, bzmin, bzmax);
11467  p[2] = hilbert_split(vertexarray, p[4], transgc[e][d][1], transgc[e][d][2],
11468  bxmin, bxmax, bymin, bymax, bzmin, bzmax);
11469  p[1] = hilbert_split(vertexarray, p[2], transgc[e][d][0], transgc[e][d][1],
11470  bxmin, bxmax, bymin, bymax, bzmin, bzmax);
11471  p[3] = hilbert_split(&(vertexarray[p[2]]), p[4] - p[2],
11472  transgc[e][d][2], transgc[e][d][3],
11473  bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[2];
11474  p[6] = hilbert_split(&(vertexarray[p[4]]), p[8] - p[4],
11475  transgc[e][d][5], transgc[e][d][6],
11476  bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4];
11477  p[5] = hilbert_split(&(vertexarray[p[4]]), p[6] - p[4],
11478  transgc[e][d][4], transgc[e][d][5],
11479  bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[4];
11480  p[7] = hilbert_split(&(vertexarray[p[6]]), p[8] - p[6],
11481  transgc[e][d][6], transgc[e][d][7],
11482  bxmin, bxmax, bymin, bymax, bzmin, bzmax) + p[6];
11483 
11484  if (b->hilbert_order > 0) {
11485  // A maximum order is prescribed.
11486  if ((depth + 1) == b->hilbert_order) {
11487  // The maximum prescribed order is reached.
11488  return;
11489  }
11490  }
11491 
11492  // Recursively sort the points in sub-boxes.
11493  for (w = 0; w < 8; w++) {
11494  // w is the local Hilbert index (NOT Gray code).
11495  // Sort into the sub-box either there are more than 2 points in it, or
11496  // the prescribed order of the curve is not reached yet.
11497  //if ((p[w+1] - p[w] > b->hilbert_limit) || (b->hilbert_order > 0)) {
11498  if ((p[w+1] - p[w]) > b->hilbert_limit) {
11499  // Calculcate the start point (ei) of the curve in this sub-box.
11500  // update e = e ^ (e(w) left_rotate (d+1)).
11501  if (w == 0) {
11502  e_w = 0;
11503  } else {
11504  // calculate e(w) = gc(2 * floor((w - 1) / 2)).
11505  k = 2 * ((w - 1) / 2);
11506  e_w = k ^ (k >> 1); // = gc(k).
11507  }
11508  k = e_w;
11509  e_w = ((k << (d+1)) & mask) | ((k >> (n-d-1)) & mask);
11510  ei = e ^ e_w;
11511  // Calulcate the direction (di) of the curve in this sub-box.
11512  // update d = (d + d(w) + 1) % n
11513  if (w == 0) {
11514  d_w = 0;
11515  } else {
11516  d_w = ((w % 2) == 0) ? tsb1mod3[w - 1] : tsb1mod3[w];
11517  }
11518  di = (d + d_w + 1) % n;
11519  // Calculate the bounding box of the sub-box.
11520  if (transgc[e][d][w] & 1) { // x-axis
11521  x1 = 0.5 * (bxmin + bxmax);
11522  x2 = bxmax;
11523  } else {
11524  x1 = bxmin;
11525  x2 = 0.5 * (bxmin + bxmax);
11526  }
11527  if (transgc[e][d][w] & 2) { // y-axis
11528  y1 = 0.5 * (bymin + bymax);
11529  y2 = bymax;
11530  } else {
11531  y1 = bymin;
11532  y2 = 0.5 * (bymin + bymax);
11533  }
11534  if (transgc[e][d][w] & 4) { // z-axis
11535  z1 = 0.5 * (bzmin + bzmax);
11536  z2 = bzmax;
11537  } else {
11538  z1 = bzmin;
11539  z2 = 0.5 * (bzmin + bzmax);
11540  }
11541  hilbert_sort3(&(vertexarray[p[w]]), p[w+1] - p[w], ei, di,
11542  x1, x2, y1, y2, z1, z2, depth+1);
11543  } // if (p[w+1] - p[w] > 1)
11544  } // w
11545 }
11546 
11548 // //
11549 // brio_multiscale_sort() Sort the points using BRIO and Hilbert curve. //
11550 // //
11552 
11553 void tetgenmesh::brio_multiscale_sort(point* vertexarray, int arraysize,
11554  int threshold, REAL ratio, int *depth)
11555 {
11556  int middle;
11557 
11558  middle = 0;
11559  if (arraysize >= threshold) {
11560  (*depth)++;
11561  middle = arraysize * ratio;
11562  brio_multiscale_sort(vertexarray, middle, threshold, ratio, depth);
11563  }
11564  // Sort the right-array (rnd-th round) using the Hilbert curve.
11565  hilbert_sort3(&(vertexarray[middle]), arraysize - middle, 0, 0, // e, d
11566  xmin, xmax, ymin, ymax, zmin, zmax, 0); // depth.
11567 }
11568 
11570 // //
11571 // randomnation() Generate a random number between 0 and 'choices' - 1. //
11572 // //
11574 
11575 unsigned long tetgenmesh::randomnation(unsigned int choices)
11576 {
11577  unsigned long newrandom;
11578 
11579  if (choices >= 714025l) {
11580  newrandom = (randomseed * 1366l + 150889l) % 714025l;
11581  randomseed = (newrandom * 1366l + 150889l) % 714025l;
11582  newrandom = newrandom * (choices / 714025l) + randomseed;
11583  if (newrandom >= choices) {
11584  return newrandom - choices;
11585  } else {
11586  return newrandom;
11587  }
11588  } else {
11589  randomseed = (randomseed * 1366l + 150889l) % 714025l;
11590  return randomseed % choices;
11591  }
11592 }
11593 
11595 // //
11596 // randomsample() Randomly sample the tetrahedra for point loation. //
11597 // //
11598 // Searching begins from one of handles: the input 'searchtet', a recently //
11599 // encountered tetrahedron 'recenttet', or from one chosen from a random //
11600 // sample. The choice is made by determining which one's origin is closest //
11601 // to the point we are searching for. //
11602 // //
11604 
11605 void tetgenmesh::randomsample(point searchpt,triface *searchtet)
11606 {
11607  tetrahedron *firsttet, *tetptr;
11608  point torg;
11609  void **sampleblock;
11610  uintptr_t alignptr;
11611  long sampleblocks, samplesperblock, samplenum;
11612  long tetblocks, i, j;
11613  REAL searchdist, dist;
11614 
11615  if (b->verbose > 2) {
11616  printf(" Random sampling tetrahedra for searching point %d.\n",
11617  pointmark(searchpt));
11618  }
11619 
11620  if (!nonconvex) {
11621  if (searchtet->tet == NULL) {
11622  // A null tet. Choose the recenttet as the starting tet.
11623  *searchtet = recenttet;
11624  }
11625 
11626  // 'searchtet' should be a valid tetrahedron. Choose the base face
11627  // whose vertices must not be 'dummypoint'.
11628  searchtet->ver = 3;
11629  // Record the distance from its origin to the searching point.
11630  torg = org(*searchtet);
11631  searchdist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
11632  (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
11633  (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
11634 
11635  // If a recently encountered tetrahedron has been recorded and has not
11636  // been deallocated, test it as a good starting point.
11637  if (recenttet.tet != searchtet->tet) {
11638  recenttet.ver = 3;
11639  torg = org(recenttet);
11640  dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
11641  (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
11642  (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
11643  if (dist < searchdist) {
11644  *searchtet = recenttet;
11645  searchdist = dist;
11646  }
11647  }
11648  } else {
11649  // The mesh is non-convex. Do not use 'recenttet'.
11650  searchdist = longest;
11651  }
11652 
11653  // Select "good" candidate using k random samples, taking the closest one.
11654  // The number of random samples taken is proportional to the fourth root
11655  // of the number of tetrahedra in the mesh.
11656  while (samples * samples * samples * samples < tetrahedrons->items) {
11657  samples++;
11658  }
11659  // Find how much blocks in current tet pool.
11660  tetblocks = (tetrahedrons->maxitems + b->tetrahedraperblock - 1)
11661  / b->tetrahedraperblock;
11662  // Find the average samples per block. Each block at least have 1 sample.
11663  samplesperblock = 1 + (samples / tetblocks);
11664  sampleblocks = samples / samplesperblock;
11665  sampleblock = tetrahedrons->firstblock;
11666  for (i = 0; i < sampleblocks; i++) {
11667  alignptr = (uintptr_t) (sampleblock + 1);
11668  firsttet = (tetrahedron *)
11669  (alignptr + (uintptr_t) tetrahedrons->alignbytes
11670  - (alignptr % (uintptr_t) tetrahedrons->alignbytes));
11671  for (j = 0; j < samplesperblock; j++) {
11672  if (i == tetblocks - 1) {
11673  // This is the last block.
11674  samplenum = randomnation((int)
11675  (tetrahedrons->maxitems - (i * b->tetrahedraperblock)));
11676  } else {
11677  samplenum = randomnation(b->tetrahedraperblock);
11678  }
11679  tetptr = (tetrahedron *)
11680  (firsttet + (samplenum * tetrahedrons->itemwords));
11681  torg = (point) tetptr[4];
11682  if (torg != (point) NULL) {
11683  dist = (searchpt[0] - torg[0]) * (searchpt[0] - torg[0]) +
11684  (searchpt[1] - torg[1]) * (searchpt[1] - torg[1]) +
11685  (searchpt[2] - torg[2]) * (searchpt[2] - torg[2]);
11686  if (dist < searchdist) {
11687  searchtet->tet = tetptr;
11688  searchtet->ver = 11; // torg = org(t);
11689  searchdist = dist;
11690  }
11691  } else {
11692  // A dead tet. Re-sample it.
11693  if (i != tetblocks - 1) j--;
11694  }
11695  }
11696  sampleblock = (void **) *sampleblock;
11697  }
11698 }
11699 
11701 // //
11702 // locate() Find a tetrahedron containing a given point. //
11703 // //
11704 // Begins its search from 'searchtet', assume there is a line segment L from //
11705 // a vertex of 'searchtet' to the query point 'searchpt', and simply walk //
11706 // towards 'searchpt' by traversing all faces intersected by L. //
11707 // //
11708 // On completion, 'searchtet' is a tetrahedron that contains 'searchpt'. The //
11709 // returned value indicates one of the following cases: //
11710 // - ONVERTEX, the search point lies on the origin of 'searchtet'. //
11711 // - ONEDGE, the search point lies on an edge of 'searchtet'. //
11712 // - ONFACE, the search point lies on a face of 'searchtet'. //
11713 // - INTET, the search point lies in the interior of 'searchtet'. //
11714 // - OUTSIDE, the search point lies outside the mesh. 'searchtet' is a //
11715 // hull face which is visible by the search point. //
11716 // //
11717 // WARNING: This routine is designed for convex triangulations, and will not //
11718 // generally work after the holes and concavities have been carved. //
11719 // //
11721 
11722 enum tetgenmesh::locateresult
11723  tetgenmesh::locate(point searchpt, triface* searchtet, int chkencflag)
11724 {
11725  point torg, tdest, tapex, toppo;
11726  enum {ORGMOVE, DESTMOVE, APEXMOVE} nextmove;
11727  REAL ori, oriorg, oridest, oriapex;
11728  enum locateresult loc = OUTSIDE;
11729  int t1ver;
11730  int s;
11731 
11732  torg = tdest = tapex = toppo = NULL;
11733 
11734  if (searchtet->tet == NULL) {
11735  // A null tet. Choose the recenttet as the starting tet.
11736  searchtet->tet = recenttet.tet;
11737  }
11738 
11739  // Check if we are in the outside of the convex hull.
11740  if (ishulltet(*searchtet)) {
11741  // Get its adjacent tet (inside the hull).
11742  searchtet->ver = 3;
11743  fsymself(*searchtet);
11744  }
11745 
11746  // Let searchtet be the face such that 'searchpt' lies above to it.
11747  for (searchtet->ver = 0; searchtet->ver < 4; searchtet->ver++) {
11748  torg = org(*searchtet);
11749  tdest = dest(*searchtet);
11750  tapex = apex(*searchtet);
11751  ori = orient3d(torg, tdest, tapex, searchpt);
11752  if (ori < 0.0) break;
11753  }
11754  if (searchtet->ver == 4) {
11755  terminatetetgen(this, 2);
11756  }
11757 
11758  // Walk through tetrahedra to locate the point.
11759  while (true) {
11760 
11761  toppo = oppo(*searchtet);
11762 
11763  // Check if the vertex is we seek.
11764  if (toppo == searchpt) {
11765  // Adjust the origin of searchtet to be searchpt.
11766  esymself(*searchtet);
11767  eprevself(*searchtet);
11768  loc = ONVERTEX; // return ONVERTEX;
11769  break;
11770  }
11771 
11772  // We enter from one of serarchtet's faces, which face do we exit?
11773  oriorg = orient3d(tdest, tapex, toppo, searchpt);
11774  oridest = orient3d(tapex, torg, toppo, searchpt);
11775  oriapex = orient3d(torg, tdest, toppo, searchpt);
11776 
11777  // Now decide which face to move. It is possible there are more than one
11778  // faces are viable moves. If so, randomly choose one.
11779  if (oriorg < 0) {
11780  if (oridest < 0) {
11781  if (oriapex < 0) {
11782  // All three faces are possible.
11783  s = randomnation(3); // 's' is in {0,1,2}.
11784  if (s == 0) {
11785  nextmove = ORGMOVE;
11786  } else if (s == 1) {
11787  nextmove = DESTMOVE;
11788  } else {
11789  nextmove = APEXMOVE;
11790  }
11791  } else {
11792  // Two faces, opposite to origin and destination, are viable.
11793  //s = randomnation(2); // 's' is in {0,1}.
11794  if (randomnation(2)) {
11795  nextmove = ORGMOVE;
11796  } else {
11797  nextmove = DESTMOVE;
11798  }
11799  }
11800  } else {
11801  if (oriapex < 0) {
11802  // Two faces, opposite to origin and apex, are viable.
11803  //s = randomnation(2); // 's' is in {0,1}.
11804  if (randomnation(2)) {
11805  nextmove = ORGMOVE;
11806  } else {
11807  nextmove = APEXMOVE;
11808  }
11809  } else {
11810  // Only the face opposite to origin is viable.
11811  nextmove = ORGMOVE;
11812  }
11813  }
11814  } else {
11815  if (oridest < 0) {
11816  if (oriapex < 0) {
11817  // Two faces, opposite to destination and apex, are viable.
11818  //s = randomnation(2); // 's' is in {0,1}.
11819  if (randomnation(2)) {
11820  nextmove = DESTMOVE;
11821  } else {
11822  nextmove = APEXMOVE;
11823  }
11824  } else {
11825  // Only the face opposite to destination is viable.
11826  nextmove = DESTMOVE;
11827  }
11828  } else {
11829  if (oriapex < 0) {
11830  // Only the face opposite to apex is viable.
11831  nextmove = APEXMOVE;
11832  } else {
11833  // The point we seek must be on the boundary of or inside this
11834  // tetrahedron. Check for boundary cases.
11835  if (oriorg == 0) {
11836  // Go to the face opposite to origin.
11837  enextesymself(*searchtet);
11838  if (oridest == 0) {
11839  eprevself(*searchtet); // edge oppo->apex
11840  if (oriapex == 0) {
11841  // oppo is duplicated with p.
11842  loc = ONVERTEX; // return ONVERTEX;
11843  break;
11844  }
11845  loc = ONEDGE; // return ONEDGE;
11846  break;
11847  }
11848  if (oriapex == 0) {
11849  enextself(*searchtet); // edge dest->oppo
11850  loc = ONEDGE; // return ONEDGE;
11851  break;
11852  }
11853  loc = ONFACE; // return ONFACE;
11854  break;
11855  }
11856  if (oridest == 0) {
11857  // Go to the face opposite to destination.
11858  eprevesymself(*searchtet);
11859  if (oriapex == 0) {
11860  eprevself(*searchtet); // edge oppo->org
11861  loc = ONEDGE; // return ONEDGE;
11862  break;
11863  }
11864  loc = ONFACE; // return ONFACE;
11865  break;
11866  }
11867  if (oriapex == 0) {
11868  // Go to the face opposite to apex
11869  esymself(*searchtet);
11870  loc = ONFACE; // return ONFACE;
11871  break;
11872  }
11873  loc = INTETRAHEDRON; // return INTETRAHEDRON;
11874  break;
11875  }
11876  }
11877  }
11878 
11879  // Move to the selected face.
11880  if (nextmove == ORGMOVE) {
11881  enextesymself(*searchtet);
11882  } else if (nextmove == DESTMOVE) {
11883  eprevesymself(*searchtet);
11884  } else {
11885  esymself(*searchtet);
11886  }
11887  if (chkencflag) {
11888  // Check if we are walking across a subface.
11889  if (issubface(*searchtet)) {
11890  loc = ENCSUBFACE;
11891  break;
11892  }
11893  }
11894  // Move to the adjacent tetrahedron (maybe a hull tetrahedron).
11895  fsymself(*searchtet);
11896  if (oppo(*searchtet) == dummypoint) {
11897  loc = OUTSIDE; // return OUTSIDE;
11898  break;
11899  }
11900 
11901  // Retreat the three vertices of the base face.
11902  torg = org(*searchtet);
11903  tdest = dest(*searchtet);
11904  tapex = apex(*searchtet);
11905 
11906  } // while (true)
11907 
11908  return loc;
11909 }
11910 
11912 // //
11913 // flippush() Push a face (possibly will be flipped) into flipstack. //
11914 // //
11915 // The face is marked. The flag is used to check the validity of the face on //
11916 // its popup. Some other flips may change it already. //
11917 // //
11919 
11920 void tetgenmesh::flippush(badface*& fstack, triface* flipface)
11921 {
11922  if (!facemarked(*flipface)) {
11923  badface *newflipface = (badface *) flippool->alloc();
11924  newflipface->tt = *flipface;
11925  markface(newflipface->tt);
11926  // Push this face into stack.
11927  newflipface->nextitem = fstack;
11928  fstack = newflipface;
11929  }
11930 }
11931 
11933 // //
11934 // incrementalflip() Incrementally flipping to construct DT. //
11935 // //
11936 // Faces need to be checked for flipping are already queued in 'flipstack'. //
11937 // Return the total number of performed flips. //
11938 // //
11939 // Comment: This routine should be only used in the incremental Delaunay //
11940 // construction. In other cases, lawsonflip3d() should be used. //
11941 // //
11942 // If the new point lies outside of the convex hull ('hullflag' is set). The //
11943 // incremental flip algorithm still works as usual. However, we must ensure //
11944 // that every flip (2-to-3 or 3-to-2) does not create a duplicated (existing)//
11945 // edge or face. Otherwise, the underlying space of the triangulation becomes//
11946 // non-manifold and it is not possible to flip further. //
11947 // Thanks to Joerg Rambau and Frank Lutz for helping in this issue. //
11948 // //
11950 
11951 int tetgenmesh::incrementalflip(point newpt, int hullflag, flipconstraints *fc)
11952 {
11953  badface *popface;
11954  triface fliptets[5], *parytet;
11955  point *pts, *parypt, pe;
11956  REAL sign, ori;
11957  int flipcount = 0;
11958  int t1ver;
11959  int i;
11960 
11961  if (b->verbose > 2) {
11962  printf(" Lawson flip (%ld faces).\n", flippool->items);
11963  }
11964 
11965  if (hullflag) {
11966  // 'newpt' lies in the outside of the convex hull.
11967  // Mark all hull vertices which are connecting to it.
11968  popface = flipstack;
11969  while (popface != NULL) {
11970  pts = (point *) popface->tt.tet;
11971  for (i = 4; i < 8; i++) {
11972  if ((pts[i] != newpt) && (pts[i] != dummypoint)) {
11973  if (!pinfected(pts[i])) {
11974  pinfect(pts[i]);
11975  cavetetvertlist->newindex((void **) &parypt);
11976  *parypt = pts[i];
11977  }
11978  }
11979  }
11980  popface = popface->nextitem;
11981  }
11982  }
11983 
11984  // Loop until the queue is empty.
11985  while (flipstack != NULL) {
11986 
11987  // Pop a face from the stack.
11988  popface = flipstack;
11989  fliptets[0] = popface->tt;
11990  flipstack = flipstack->nextitem; // The next top item in stack.
11991  flippool->dealloc((void *) popface);
11992 
11993  // Skip it if it is a dead tet (destroyed by previous flips).
11994  if (isdeadtet(fliptets[0])) continue;
11995  // Skip it if it is not the same tet as we saved.
11996  if (!facemarked(fliptets[0])) continue;
11997 
11998  unmarkface(fliptets[0]);
11999 
12000  if ((point) fliptets[0].tet[7] == dummypoint) {
12001  // It must be a hull edge.
12002  fliptets[0].ver = epivot[fliptets[0].ver];
12003  // A hull edge. The current convex hull may be enlarged.
12004  fsym(fliptets[0], fliptets[1]);
12005  pts = (point *) fliptets[1].tet;
12006  ori = orient3d(pts[4], pts[5], pts[6], newpt);
12007  if (ori < 0) {
12008  // Visible. The convex hull will be enlarged.
12009  // Decide which flip (2-to-3, 3-to-2, or 4-to-1) to use.
12010  // Check if the tet [a,c,e,d] or [c,b,e,d] exists.
12011  enext(fliptets[1], fliptets[2]);
12012  eprev(fliptets[1], fliptets[3]);
12013  fnextself(fliptets[2]); // [a,c,e,*]
12014  fnextself(fliptets[3]); // [c,b,e,*]
12015  if (oppo(fliptets[2]) == newpt) {
12016  if (oppo(fliptets[3]) == newpt) {
12017  // Both tets exist! A 4-to-1 flip is found.
12018  terminatetetgen(this, 2); // Report a bug.
12019  } else {
12020  esym(fliptets[2], fliptets[0]);
12021  fnext(fliptets[0], fliptets[1]);
12022  fnext(fliptets[1], fliptets[2]);
12023  // Perform a 3-to-2 flip. Replace edge [c,a] by face [d,e,b].
12024  // This corresponds to my standard labels, where edge [e,d] is
12025  // repalced by face [a,b,c], and a is the new vertex.
12026  // [0] [c,a,d,e] (d = newpt)
12027  // [1] [c,a,e,b] (c = dummypoint)
12028  // [2] [c,a,b,d]
12029  flip32(fliptets, 1, fc);
12030  }
12031  } else {
12032  if (oppo(fliptets[3]) == newpt) {
12033  fnext(fliptets[3], fliptets[0]);
12034  fnext(fliptets[0], fliptets[1]);
12035  fnext(fliptets[1], fliptets[2]);
12036  // Perform a 3-to-2 flip. Replace edge [c,b] by face [d,a,e].
12037  // [0] [c,b,d,a] (d = newpt)
12038  // [1] [c,b,a,e] (c = dummypoint)
12039  // [2] [c,b,e,d]
12040  flip32(fliptets, 1, fc);
12041  } else {
12042  if (hullflag) {
12043  // Reject this flip if pe is already marked.
12044  pe = oppo(fliptets[1]);
12045  if (!pinfected(pe)) {
12046  pinfect(pe);
12047  cavetetvertlist->newindex((void **) &parypt);
12048  *parypt = pe;
12049  // Perform a 2-to-3 flip.
12050  flip23(fliptets, 1, fc);
12051  } else {
12052  // Reject this flip.
12053  flipcount--;
12054  }
12055  } else {
12056  // Perform a 2-to-3 flip. Replace face [a,b,c] by edge [e,d].
12057  // [0] [a,b,c,d], d = newpt.
12058  // [1] [b,a,c,e], c = dummypoint.
12059  flip23(fliptets, 1, fc);
12060  }
12061  }
12062  }
12063  flipcount++;
12064  }
12065  continue;
12066  } // if (dummypoint)
12067 
12068  fsym(fliptets[0], fliptets[1]);
12069  if ((point) fliptets[1].tet[7] == dummypoint) {
12070  // A hull face is locally Delaunay.
12071  continue;
12072  }
12073  // Check if the adjacent tet has already been tested.
12074  if (marktested(fliptets[1])) {
12075  // It has been tested and it is Delaunay.
12076  continue;
12077  }
12078 
12079  // Test whether the face is locally Delaunay or not.
12080  pts = (point *) fliptets[1].tet;
12081  if (b->weighted) {
12082  sign = orient4d_s(pts[4], pts[5], pts[6], pts[7], newpt,
12083  pts[4][3], pts[5][3], pts[6][3], pts[7][3],
12084  newpt[3]);
12085  } else {
12086  sign = insphere_s(pts[4], pts[5], pts[6], pts[7], newpt);
12087  }
12088 
12089 
12090  if (sign < 0) {
12091  point pd = newpt;
12092  point pe = oppo(fliptets[1]);
12093  // Check the convexity of its three edges. Stop checking either a
12094  // locally non-convex edge (ori < 0) or a flat edge (ori = 0) is
12095  // encountered, and 'fliptet' represents that edge.
12096  for (i = 0; i < 3; i++) {
12097  ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe);
12098  if (ori <= 0) break;
12099  enextself(fliptets[0]);
12100  }
12101  if (ori > 0) {
12102  // A 2-to-3 flip is found.
12103  // [0] [a,b,c,d],
12104  // [1] [b,a,c,e]. no dummypoint.
12105  flip23(fliptets, 0, fc);
12106  flipcount++;
12107  } else { // ori <= 0
12108  // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat,
12109  // where the edge [a',b'] is one of [a,b], [b,c], and [c,a].
12110  // Check if there are three or four tets sharing at this edge.
12111  esymself(fliptets[0]); // [b,a,d,c]
12112  for (i = 0; i < 3; i++) {
12113  fnext(fliptets[i], fliptets[i+1]);
12114  }
12115  if (fliptets[3].tet == fliptets[0].tet) {
12116  // A 3-to-2 flip is found. (No hull tet.)
12117  flip32(fliptets, 0, fc);
12118  flipcount++;
12119  } else {
12120  // There are more than 3 tets at this edge.
12121  fnext(fliptets[3], fliptets[4]);
12122  if (fliptets[4].tet == fliptets[0].tet) {
12123  if (ori == 0) {
12124  // A 4-to-4 flip is found. (Two hull tets may be involved.)
12125  // Current tets in 'fliptets':
12126  // [0] [b,a,d,c] (d may be newpt)
12127  // [1] [b,a,c,e]
12128  // [2] [b,a,e,f] (f may be dummypoint)
12129  // [3] [b,a,f,d]
12130  esymself(fliptets[0]); // [a,b,c,d]
12131  // A 2-to-3 flip replaces face [a,b,c] by edge [e,d].
12132  // This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]).
12133  // It will be removed by the followed 3-to-2 flip.
12134  flip23(fliptets, 0, fc); // No hull tet.
12135  fnext(fliptets[3], fliptets[1]);
12136  fnext(fliptets[1], fliptets[2]);
12137  // Current tets in 'fliptets':
12138  // [0] [...]
12139  // [1] [b,a,d,e] (degenerated, d may be new point).
12140  // [2] [b,a,e,f] (f may be dummypoint)
12141  // [3] [b,a,f,d]
12142  // A 3-to-2 flip replaces edge [b,a] by face [d,e,f].
12143  // Hull tets may be involved (f may be dummypoint).
12144  flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc);
12145  flipcount++;
12146  }
12147  }
12148  }
12149  } // ori
12150  } else {
12151  // The adjacent tet is Delaunay. Mark it to avoid testing it again.
12152  marktest(fliptets[1]);
12153  // Save it for unmarking it later.
12154  cavebdrylist->newindex((void **) &parytet);
12155  *parytet = fliptets[1];
12156  }
12157 
12158  } // while (flipstack)
12159 
12160  // Unmark saved tetrahedra.
12161  for (i = 0; i < cavebdrylist->objects; i++) {
12162  parytet = (triface *) fastlookup(cavebdrylist, i);
12163  unmarktest(*parytet);
12164  }
12165  cavebdrylist->restart();
12166 
12167  if (hullflag) {
12168  // Unmark infected vertices.
12169  for (i = 0; i < cavetetvertlist->objects; i++) {
12170  parypt = (point *) fastlookup(cavetetvertlist, i);
12171  puninfect(*parypt);
12172  }
12173  cavetetvertlist->restart();
12174  }
12175 
12176 
12177  return flipcount;
12178 }
12179 
12181 // //
12182 // initialdelaunay() Create an initial Delaunay tetrahedralization. //
12183 // //
12184 // The tetrahedralization contains only one tetrahedron abcd, and four hull //
12185 // tetrahedra. The points pa, pb, pc, and pd must be linearly independent. //
12186 // //
12188 
12189 void tetgenmesh::initialdelaunay(point pa, point pb, point pc, point pd)
12190 {
12191  triface firsttet, tetopa, tetopb, tetopc, tetopd;
12192  triface worktet, worktet1;
12193 
12194  if (b->verbose > 2) {
12195  printf(" Create init tet (%d, %d, %d, %d)\n", pointmark(pa),
12196  pointmark(pb), pointmark(pc), pointmark(pd));
12197  }
12198 
12199  // Create the first tetrahedron.
12200  maketetrahedron(&firsttet);
12201  setvertices(firsttet, pa, pb, pc, pd);
12202  // Create four hull tetrahedra.
12203  maketetrahedron(&tetopa);
12204  setvertices(tetopa, pb, pc, pd, dummypoint);
12205  maketetrahedron(&tetopb);
12206  setvertices(tetopb, pc, pa, pd, dummypoint);
12207  maketetrahedron(&tetopc);
12208  setvertices(tetopc, pa, pb, pd, dummypoint);
12209  maketetrahedron(&tetopd);
12210  setvertices(tetopd, pb, pa, pc, dummypoint);
12211  hullsize += 4;
12212 
12213  // Connect hull tetrahedra to firsttet (at four faces of firsttet).
12214  bond(firsttet, tetopd);
12215  esym(firsttet, worktet);
12216  bond(worktet, tetopc); // ab
12217  enextesym(firsttet, worktet);
12218  bond(worktet, tetopa); // bc
12219  eprevesym(firsttet, worktet);
12220  bond(worktet, tetopb); // ca
12221 
12222  // Connect hull tetrahedra together (at six edges of firsttet).
12223  esym(tetopc, worktet);
12224  esym(tetopd, worktet1);
12225  bond(worktet, worktet1); // ab
12226  esym(tetopa, worktet);
12227  eprevesym(tetopd, worktet1);
12228  bond(worktet, worktet1); // bc
12229  esym(tetopb, worktet);
12230  enextesym(tetopd, worktet1);
12231  bond(worktet, worktet1); // ca
12232  eprevesym(tetopc, worktet);
12233  enextesym(tetopb, worktet1);
12234  bond(worktet, worktet1); // da
12235  eprevesym(tetopa, worktet);
12236  enextesym(tetopc, worktet1);
12237  bond(worktet, worktet1); // db
12238  eprevesym(tetopb, worktet);
12239  enextesym(tetopa, worktet1);
12240  bond(worktet, worktet1); // dc
12241 
12242  // Set the vertex type.
12243  if (pointtype(pa) == UNUSEDVERTEX) {
12244  setpointtype(pa, VOLVERTEX);
12245  }
12246  if (pointtype(pb) == UNUSEDVERTEX) {
12247  setpointtype(pb, VOLVERTEX);
12248  }
12249  if (pointtype(pc) == UNUSEDVERTEX) {
12250  setpointtype(pc, VOLVERTEX);
12251  }
12252  if (pointtype(pd) == UNUSEDVERTEX) {
12253  setpointtype(pd, VOLVERTEX);
12254  }
12255 
12256  setpoint2tet(pa, encode(firsttet));
12257  setpoint2tet(pb, encode(firsttet));
12258  setpoint2tet(pc, encode(firsttet));
12259  setpoint2tet(pd, encode(firsttet));
12260 
12261  // Remember the first tetrahedron.
12262  recenttet = firsttet;
12263 }
12264 
12266 // //
12267 // incrementaldelaunay() Create a Delaunay tetrahedralization by //
12268 // the incremental approach. //
12269 // //
12271 
12272 
12273 void tetgenmesh::incrementaldelaunay(clock_t& tv)
12274 {
12275  triface searchtet;
12276  point *permutarray, swapvertex;
12277  REAL v1[3], v2[3], n[3];
12278  REAL bboxsize, bboxsize2, bboxsize3, ori;
12279  int randindex;
12280  int ngroup = 0;
12281  int i, j;
12282 
12283  if (!b->quiet) {
12284  printf("Delaunizing vertices...\n");
12285  }
12286 
12287  // Form a random permuation (uniformly at random) of the set of vertices.
12288  permutarray = new point[in->numberofpoints];
12289  points->traversalinit();
12290 
12291  if (b->no_sort) {
12292  if (b->verbose) {
12293  printf(" Using the input order.\n");
12294  }
12295  for (i = 0; i < in->numberofpoints; i++) {
12296  permutarray[i] = (point) points->traverse();
12297  }
12298  } else {
12299  if (b->verbose) {
12300  printf(" Permuting vertices.\n");
12301  }
12302  srand(in->numberofpoints);
12303  for (i = 0; i < in->numberofpoints; i++) {
12304  randindex = rand() % (i + 1); // randomnation(i + 1);
12305  permutarray[i] = permutarray[randindex];
12306  permutarray[randindex] = (point) points->traverse();
12307  }
12308  if (b->brio_hilbert) { // -b option
12309  if (b->verbose) {
12310  printf(" Sorting vertices.\n");
12311  }
12312  hilbert_init(in->mesh_dim);
12313  brio_multiscale_sort(permutarray, in->numberofpoints, b->brio_threshold,
12314  b->brio_ratio, &ngroup);
12315  }
12316  }
12317 
12318  tv = clock(); // Remember the time for sorting points.
12319 
12320  // Calculate the diagonal size of its bounding box.
12321  bboxsize = sqrt(norm2(xmax - xmin, ymax - ymin, zmax - zmin));
12322  bboxsize2 = bboxsize * bboxsize;
12323  bboxsize3 = bboxsize2 * bboxsize;
12324 
12325  // Make sure the second vertex is not identical with the first one.
12326  i = 1;
12327  while ((distance(permutarray[0],permutarray[i])/bboxsize)<b->epsilon) {
12328  i++;
12329  if (i == in->numberofpoints - 1) {
12330  printf("Exception: All vertices are (nearly) identical (Tol = %g).\n",
12331  b->epsilon);
12332  terminatetetgen(this, 10);
12333  }
12334  }
12335  if (i > 1) {
12336  // Swap to move the non-identical vertex from index i to index 1.
12337  swapvertex = permutarray[i];
12338  permutarray[i] = permutarray[1];
12339  permutarray[1] = swapvertex;
12340  }
12341 
12342  // Make sure the third vertex is not collinear with the first two.
12343  // Acknowledgement: Thanks Jan Pomplun for his correction by using
12344  // epsilon^2 and epsilon^3 (instead of epsilon). 2013-08-15.
12345  i = 2;
12346  for (j = 0; j < 3; j++) {
12347  v1[j] = permutarray[1][j] - permutarray[0][j];
12348  v2[j] = permutarray[i][j] - permutarray[0][j];
12349  }
12350  cross(v1, v2, n);
12351  while ((sqrt(norm2(n[0], n[1], n[2])) / bboxsize2) < b->epsilon) {
12352  i++;
12353  if (i == in->numberofpoints - 1) {
12354  printf("Exception: All vertices are (nearly) collinear (Tol = %g).\n",
12355  b->epsilon);
12356  terminatetetgen(this, 10);
12357  }
12358  for (j = 0; j < 3; j++) {
12359  v2[j] = permutarray[i][j] - permutarray[0][j];
12360  }
12361  cross(v1, v2, n);
12362  }
12363  if (i > 2) {
12364  // Swap to move the non-identical vertex from index i to index 1.
12365  swapvertex = permutarray[i];
12366  permutarray[i] = permutarray[2];
12367  permutarray[2] = swapvertex;
12368  }
12369 
12370  // Make sure the fourth vertex is not coplanar with the first three.
12371  i = 3;
12372  ori = orient3dfast(permutarray[0], permutarray[1], permutarray[2],
12373  permutarray[i]);
12374  while ((fabs(ori) / bboxsize3) < b->epsilon) {
12375  i++;
12376  if (i == in->numberofpoints) {
12377  printf("Exception: All vertices are coplanar (Tol = %g).\n",
12378  b->epsilon);
12379  terminatetetgen(this, 10);
12380  }
12381  ori = orient3dfast(permutarray[0], permutarray[1], permutarray[2],
12382  permutarray[i]);
12383  }
12384  if (i > 3) {
12385  // Swap to move the non-identical vertex from index i to index 1.
12386  swapvertex = permutarray[i];
12387  permutarray[i] = permutarray[3];
12388  permutarray[3] = swapvertex;
12389  }
12390 
12391  // Orient the first four vertices in permutarray so that they follow the
12392  // right-hand rule.
12393  if (ori > 0.0) {
12394  // Swap the first two vertices.
12395  swapvertex = permutarray[0];
12396  permutarray[0] = permutarray[1];
12397  permutarray[1] = swapvertex;
12398  }
12399 
12400  // Create the initial Delaunay tetrahedralization.
12401  initialdelaunay(permutarray[0], permutarray[1], permutarray[2],
12402  permutarray[3]);
12403 
12404  if (b->verbose) {
12405  printf(" Incrementally inserting vertices.\n");
12406  }
12407  insertvertexflags ivf;
12408  flipconstraints fc;
12409 
12410  // Choose algorithm: Bowyer-Watson (default) or Incremental Flip
12411  if (b->incrflip) {
12412  ivf.bowywat = 0;
12413  ivf.lawson = 1;
12414  fc.enqflag = 1;
12415  } else {
12416  ivf.bowywat = 1;
12417  ivf.lawson = 0;
12418  }
12419 
12420 
12421  for (i = 4; i < in->numberofpoints; i++) {
12422  if (pointtype(permutarray[i]) == UNUSEDVERTEX) {
12423  setpointtype(permutarray[i], VOLVERTEX);
12424  }
12425  if (b->brio_hilbert || b->no_sort) { // -b or -b/1
12426  // Start the last updated tet.
12427  searchtet.tet = recenttet.tet;
12428  } else { // -b0
12429  // Randomly choose the starting tet for point location.
12430  searchtet.tet = NULL;
12431  }
12432  ivf.iloc = (int) OUTSIDE;
12433  // Insert the vertex.
12434  if (insertpoint(permutarray[i], &searchtet, NULL, NULL, &ivf)) {
12435  if (flipstack != NULL) {
12436  // Perform flip to recover Delaunayness.
12437  incrementalflip(permutarray[i], (ivf.iloc == (int) OUTSIDE), &fc);
12438  }
12439  } else {
12440  if (ivf.iloc == (int) ONVERTEX) {
12441  // The point already exists. Mark it and do nothing on it.
12442  swapvertex = org(searchtet);
12443  if (b->object != tetgenbehavior::STL) {
12444  if (!b->quiet) {
12445  printf("Warning: Point #%d is coincident with #%d. Ignored!\n",
12446  pointmark(permutarray[i]), pointmark(swapvertex));
12447  }
12448  }
12449  setpoint2ppt(permutarray[i], swapvertex);
12450  setpointtype(permutarray[i], DUPLICATEDVERTEX);
12451  dupverts++;
12452  } else if (ivf.iloc == (int) NEARVERTEX) {
12453  swapvertex = org(searchtet);
12454  if (!b->quiet) {
12455  printf("Warning: Point %d is replaced by point %d.\n",
12456  pointmark(permutarray[i]), pointmark(swapvertex));
12457  printf(" Avoid creating a very short edge (len = %g) (< %g).\n",
12458  permutarray[i][3], minedgelength);
12459  printf(" You may try a smaller tolerance (-T) (current is %g)\n",
12460  b->epsilon);
12461  printf(" or use the option -M0/1 to avoid such replacement.\n");
12462  }
12463  // Remember it is a duplicated point.
12464  setpoint2ppt(permutarray[i], swapvertex);
12465  setpointtype(permutarray[i], DUPLICATEDVERTEX);
12466  dupverts++;
12467  } else if (ivf.iloc == (int) NONREGULAR) {
12468  // The point is non-regular. Skipped.
12469  if (b->verbose) {
12470  printf(" Point #%d is non-regular, skipped.\n",
12471  pointmark(permutarray[i]));
12472  }
12473  setpointtype(permutarray[i], NREGULARVERTEX);
12474  nonregularcount++;
12475  }
12476  }
12477  }
12478 
12479 
12480 
12481  delete [] permutarray;
12482 }
12483 
12487 
12491 
12493 // //
12494 // flipshpush() Push a facet edge into flip stack. //
12495 // //
12497 
12498 void tetgenmesh::flipshpush(face* flipedge)
12499 {
12500  badface *newflipface;
12501 
12502  newflipface = (badface *) flippool->alloc();
12503  newflipface->ss = *flipedge;
12504  newflipface->forg = sorg(*flipedge);
12505  newflipface->fdest = sdest(*flipedge);
12506  newflipface->nextitem = flipstack;
12507  flipstack = newflipface;
12508 }
12509 
12511 // //
12512 // flip22() Perform a 2-to-2 flip in surface mesh. //
12513 // //
12514 // 'flipfaces' is an array of two subfaces. On input, they are [a,b,c] and //
12515 // [b,a,d]. On output, they are [c,d,b] and [d,c,a]. As a result, edge [a,b] //
12516 // is replaced by edge [c,d]. //
12517 // //
12519 
12520 void tetgenmesh::flip22(face* flipfaces, int flipflag, int chkencflag)
12521 {
12522  face bdedges[4], outfaces[4], infaces[4];
12523  face bdsegs[4];
12524  face checkface;
12525  point pa, pb, pc, pd;
12526  int i;
12527 
12528  pa = sorg(flipfaces[0]);
12529  pb = sdest(flipfaces[0]);
12530  pc = sapex(flipfaces[0]);
12531  pd = sapex(flipfaces[1]);
12532 
12533  if (sorg(flipfaces[1]) != pb) {
12534  sesymself(flipfaces[1]);
12535  }
12536 
12537  flip22count++;
12538 
12539  // Collect the four boundary edges.
12540  senext(flipfaces[0], bdedges[0]);
12541  senext2(flipfaces[0], bdedges[1]);
12542  senext(flipfaces[1], bdedges[2]);
12543  senext2(flipfaces[1], bdedges[3]);
12544 
12545  // Collect outer boundary faces.
12546  for (i = 0; i < 4; i++) {
12547  spivot(bdedges[i], outfaces[i]);
12548  infaces[i] = outfaces[i];
12549  sspivot(bdedges[i], bdsegs[i]);
12550  if (outfaces[i].sh != NULL) {
12551  if (isshsubseg(bdedges[i])) {
12552  spivot(infaces[i], checkface);
12553  while (checkface.sh != bdedges[i].sh) {
12554  infaces[i] = checkface;
12555  spivot(infaces[i], checkface);
12556  }
12557  }
12558  }
12559  }
12560 
12561  // The flags set in these two subfaces do not change.
12562  // Shellmark does not change.
12563  // area constraint does not change.
12564 
12565  // Transform [a,b,c] -> [c,d,b].
12566  setshvertices(flipfaces[0], pc, pd, pb);
12567  // Transform [b,a,d] -> [d,c,a].
12568  setshvertices(flipfaces[1], pd, pc, pa);
12569 
12570  // Update the point-to-subface map.
12571  if (pointtype(pa) == FREEFACETVERTEX) {
12572  setpoint2sh(pa, sencode(flipfaces[1]));
12573  }
12574  if (pointtype(pb) == FREEFACETVERTEX) {
12575  setpoint2sh(pb, sencode(flipfaces[0]));
12576  }
12577  if (pointtype(pc) == FREEFACETVERTEX) {
12578  setpoint2sh(pc, sencode(flipfaces[0]));
12579  }
12580  if (pointtype(pd) == FREEFACETVERTEX) {
12581  setpoint2sh(pd, sencode(flipfaces[0]));
12582  }
12583 
12584  // Reconnect boundary edges to outer boundary faces.
12585  for (i = 0; i < 4; i++) {
12586  if (outfaces[(3 + i) % 4].sh != NULL) {
12587  // Make sure that the subface has the ori as the segment.
12588  if (bdsegs[(3 + i) % 4].sh != NULL) {
12589  bdsegs[(3 + i) % 4].shver = 0;
12590  if (sorg(bdedges[i]) != sorg(bdsegs[(3 + i) % 4])) {
12591  sesymself(bdedges[i]);
12592  }
12593  }
12594  sbond1(bdedges[i], outfaces[(3 + i) % 4]);
12595  sbond1(infaces[(3 + i) % 4], bdedges[i]);
12596  } else {
12597  sdissolve(bdedges[i]);
12598  }
12599  if (bdsegs[(3 + i) % 4].sh != NULL) {
12600  ssbond(bdedges[i], bdsegs[(3 + i) % 4]);
12601  if (chkencflag & 1) {
12602  // Queue this segment for encroaching check.
12603  enqueuesubface(badsubsegs, &(bdsegs[(3 + i) % 4]));
12604  }
12605  } else {
12606  ssdissolve(bdedges[i]);
12607  }
12608  }
12609 
12610  if (chkencflag & 2) {
12611  // Queue the flipped subfaces for quality/encroaching checks.
12612  for (i = 0; i < 2; i++) {
12613  enqueuesubface(badsubfacs, &(flipfaces[i]));
12614  }
12615  }
12616 
12617  recentsh = flipfaces[0];
12618 
12619  if (flipflag) {
12620  // Put the boundary edges into flip stack.
12621  for (i = 0; i < 4; i++) {
12622  flipshpush(&(bdedges[i]));
12623  }
12624  }
12625 }
12626 
12628 // //
12629 // flip31() Remove a vertex by transforming 3-to-1 subfaces. //
12630 // //
12631 // 'flipfaces' is an array of subfaces. Its length is at least 4. On input, //
12632 // the first three faces are: [p,a,b], [p,b,c], and [p,c,a]. This routine //
12633 // replaces them by one face [a,b,c], it is returned in flipfaces[3]. //
12634 // //
12635 // NOTE: The three old subfaces are not deleted within this routine. They //
12636 // still hold pointers to their adjacent subfaces. These informations are //
12637 // needed by the routine 'sremovevertex()' for recovering a segment. //
12638 // The caller of this routine must delete the old subfaces after their uses. //
12639 // //
12641 
12642 void tetgenmesh::flip31(face* flipfaces, int flipflag)
12643 {
12644  face bdedges[3], outfaces[3], infaces[3];
12645  face bdsegs[3];
12646  face checkface;
12647  point pa, pb, pc;
12648  int i;
12649 
12650  pa = sdest(flipfaces[0]);
12651  pb = sdest(flipfaces[1]);
12652  pc = sdest(flipfaces[2]);
12653 
12654  flip31count++;
12655 
12656  // Collect all infos at the three boundary edges.
12657  for (i = 0; i < 3; i++) {
12658  senext(flipfaces[i], bdedges[i]);
12659  spivot(bdedges[i], outfaces[i]);
12660  infaces[i] = outfaces[i];
12661  sspivot(bdedges[i], bdsegs[i]);
12662  if (outfaces[i].sh != NULL) {
12663  if (isshsubseg(bdedges[i])) {
12664  spivot(infaces[i], checkface);
12665  while (checkface.sh != bdedges[i].sh) {
12666  infaces[i] = checkface;
12667  spivot(infaces[i], checkface);
12668  }
12669  }
12670  }
12671  } // i
12672 
12673  // Create a new subface.
12674  makeshellface(subfaces, &(flipfaces[3]));
12675  setshvertices(flipfaces[3], pa, pb,pc);
12676  setshellmark(flipfaces[3], shellmark(flipfaces[0]));
12677  if (checkconstraints) {
12678  //area = areabound(flipfaces[0]);
12679  setareabound(flipfaces[3], areabound(flipfaces[0]));
12680  }
12681  if (useinsertradius) {
12682  setfacetindex(flipfaces[3], getfacetindex(flipfaces[0]));
12683  }
12684 
12685  // Update the point-to-subface map.
12686  if (pointtype(pa) == FREEFACETVERTEX) {
12687  setpoint2sh(pa, sencode(flipfaces[3]));
12688  }
12689  if (pointtype(pb) == FREEFACETVERTEX) {
12690  setpoint2sh(pb, sencode(flipfaces[3]));
12691  }
12692  if (pointtype(pc) == FREEFACETVERTEX) {
12693  setpoint2sh(pc, sencode(flipfaces[3]));
12694  }
12695 
12696  // Update the three new boundary edges.
12697  bdedges[0] = flipfaces[3]; // [a,b]
12698  senext(flipfaces[3], bdedges[1]); // [b,c]
12699  senext2(flipfaces[3], bdedges[2]); // [c,a]
12700 
12701  // Reconnect boundary edges to outer boundary faces.
12702  for (i = 0; i < 3; i++) {
12703  if (outfaces[i].sh != NULL) {
12704  // Make sure that the subface has the ori as the segment.
12705  if (bdsegs[i].sh != NULL) {
12706  bdsegs[i].shver = 0;
12707  if (sorg(bdedges[i]) != sorg(bdsegs[i])) {
12708  sesymself(bdedges[i]);
12709  }
12710  }
12711  sbond1(bdedges[i], outfaces[i]);
12712  sbond1(infaces[i], bdedges[i]);
12713  }
12714  if (bdsegs[i].sh != NULL) {
12715  ssbond(bdedges[i], bdsegs[i]);
12716  }
12717  }
12718 
12719  recentsh = flipfaces[3];
12720 
12721  if (flipflag) {
12722  // Put the boundary edges into flip stack.
12723  for (i = 0; i < 3; i++) {
12724  flipshpush(&(bdedges[i]));
12725  }
12726  }
12727 }
12728 
12730 // //
12731 // lawsonflip() Flip non-locally Delaunay edges. //
12732 // //
12734 
12735 long tetgenmesh::lawsonflip()
12736 {
12737  badface *popface;
12738  face flipfaces[2];
12739  point pa, pb, pc, pd;
12740  REAL sign;
12741  long flipcount = 0;
12742 
12743  if (b->verbose > 2) {
12744  printf(" Lawson flip %ld edges.\n", flippool->items);
12745  }
12746 
12747  while (flipstack != (badface *) NULL) {
12748 
12749  // Pop an edge from the stack.
12750  popface = flipstack;
12751  flipfaces[0] = popface->ss;
12752  pa = popface->forg;
12753  pb = popface->fdest;
12754  flipstack = popface->nextitem; // The next top item in stack.
12755  flippool->dealloc((void *) popface);
12756 
12757  // Skip it if it is dead.
12758  if (flipfaces[0].sh[3] == NULL) continue;
12759  // Skip it if it is not the same edge as we saved.
12760  if ((sorg(flipfaces[0]) != pa) || (sdest(flipfaces[0]) != pb)) continue;
12761  // Skip it if it is a subsegment.
12762  if (isshsubseg(flipfaces[0])) continue;
12763 
12764  // Get the adjacent face.
12765  spivot(flipfaces[0], flipfaces[1]);
12766  if (flipfaces[1].sh == NULL) continue; // Skip a hull edge.
12767  pc = sapex(flipfaces[0]);
12768  pd = sapex(flipfaces[1]);
12769 
12770  sign = incircle3d(pa, pb, pc, pd);
12771 
12772  if (sign < 0) {
12773  // It is non-locally Delaunay. Flip it.
12774  flip22(flipfaces, 1, 0);
12775  flipcount++;
12776  }
12777  }
12778 
12779  if (b->verbose > 2) {
12780  printf(" Performed %ld flips.\n", flipcount);
12781  }
12782 
12783  return flipcount;
12784 }
12785 
12787 // //
12788 // sinsertvertex() Insert a vertex into a triangulation of a facet. //
12789 // //
12790 // This function uses three global arrays: 'caveshlist', 'caveshbdlist', and //
12791 // 'caveshseglist'. On return, 'caveshlist' contains old subfaces in C(p), //
12792 // 'caveshbdlist' contains new subfaces in C(p). If the new point lies on a //
12793 // segment, 'cavesegshlist' returns the two new subsegments. //
12794 // //
12795 // 'iloc' suggests the location of the point. If it is OUTSIDE, this routine //
12796 // will first locate the point. It starts searching from 'searchsh' or 'rec- //
12797 // entsh' if 'searchsh' is NULL. //
12798 // //
12799 // If 'bowywat' is set (1), the Bowyer-Watson algorithm is used to insert //
12800 // the vertex. Otherwise, only insert the vertex in the initial cavity. //
12801 // //
12802 // If 'iloc' is 'INSTAR', this means the cavity of this vertex was already //
12803 // provided in the list 'caveshlist'. //
12804 // //
12805 // If 'splitseg' is not NULL, the new vertex lies on the segment and it will //
12806 // be split. 'iloc' must be either 'ONEDGE' or 'INSTAR'. //
12807 // //
12808 // 'rflag' (rounding) is a parameter passed to slocate() function. If it is //
12809 // set, after the location of the point is found, either ONEDGE or ONFACE, //
12810 // round the result using an epsilon. //
12811 // //
12812 // NOTE: the old subfaces in C(p) are not deleted. They're needed in case we //
12813 // want to remove the new point immediately. //
12814 // //
12816 
12817 int tetgenmesh::sinsertvertex(point insertpt, face *searchsh, face *splitseg,
12818  int iloc, int bowywat, int rflag)
12819 {
12820  face cavesh, neighsh, *parysh;
12821  face newsh, casout, casin;
12822  face checkseg;
12823  point pa, pb;
12824  enum locateresult loc = OUTSIDE;
12825  REAL sign, ori;
12826  int i, j;
12827 
12828  if (b->verbose > 2) {
12829  printf(" Insert facet point %d.\n", pointmark(insertpt));
12830  }
12831 
12832  if (bowywat == 3) {
12833  loc = INSTAR;
12834  }
12835 
12836  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
12837  // A segment is going to be split, no point location.
12838  spivot(*splitseg, *searchsh);
12839  if (loc != INSTAR) loc = ONEDGE;
12840  } else {
12841  if (loc != INSTAR) loc = (enum locateresult) iloc;
12842  if (loc == OUTSIDE) {
12843  // Do point location in surface mesh.
12844  if (searchsh->sh == NULL) {
12845  *searchsh = recentsh;
12846  }
12847  // Search the vertex. An above point must be provided ('aflag' = 1).
12848  loc = slocate(insertpt, searchsh, 1, 1, rflag);
12849  }
12850  }
12851 
12852 
12853  // Form the initial sC(p).
12854  if (loc == ONFACE) {
12855  // Add the face into list (in B-W cavity).
12856  smarktest(*searchsh);
12857  caveshlist->newindex((void **) &parysh);
12858  *parysh = *searchsh;
12859  } else if (loc == ONEDGE) {
12860  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
12861  splitseg->shver = 0;
12862  pa = sorg(*splitseg);
12863  } else {
12864  pa = sorg(*searchsh);
12865  }
12866  if (searchsh->sh != NULL) {
12867  // Collect all subfaces share at this edge.
12868  neighsh = *searchsh;
12869  while (1) {
12870  // Adjust the origin of its edge to be 'pa'.
12871  if (sorg(neighsh) != pa) sesymself(neighsh);
12872  // Add this face into list (in B-W cavity).
12873  smarktest(neighsh);
12874  caveshlist->newindex((void **) &parysh);
12875  *parysh = neighsh;
12876  // Add this face into face-at-splitedge list.
12877  cavesegshlist->newindex((void **) &parysh);
12878  *parysh = neighsh;
12879  // Go to the next face at the edge.
12880  spivotself(neighsh);
12881  // Stop if all faces at the edge have been visited.
12882  if (neighsh.sh == searchsh->sh) break;
12883  if (neighsh.sh == NULL) break;
12884  }
12885  } // If (not a non-dangling segment).
12886  } else if (loc == ONVERTEX) {
12887  return (int) loc;
12888  } else if (loc == OUTSIDE) {
12889  // Comment: This should only happen during the surface meshing step.
12890  // Enlarge the convex hull of the triangulation by including p.
12891  // An above point of the facet is set in 'dummypoint' to replace
12892  // orient2d tests by orient3d tests.
12893  // Imagine that the current edge a->b (in 'searchsh') is horizontal in a
12894  // plane, and a->b is directed from left to right, p lies above a->b.
12895  // Find the right-most edge of the triangulation which is visible by p.
12896  neighsh = *searchsh;
12897  while (1) {
12898  senext2self(neighsh);
12899  spivot(neighsh, casout);
12900  if (casout.sh == NULL) {
12901  // A convex hull edge. Is it visible by p.
12902  ori = orient3d(sorg(neighsh), sdest(neighsh), dummypoint, insertpt);
12903  if (ori < 0) {
12904  *searchsh = neighsh; // Visible, update 'searchsh'.
12905  } else {
12906  break; // 'searchsh' is the right-most visible edge.
12907  }
12908  } else {
12909  if (sorg(casout) != sdest(neighsh)) sesymself(casout);
12910  neighsh = casout;
12911  }
12912  }
12913  // Create new triangles for all visible edges of p (from right to left).
12914  casin.sh = NULL; // No adjacent face at right.
12915  pa = sorg(*searchsh);
12916  pb = sdest(*searchsh);
12917  while (1) {
12918  // Create a new subface on top of the (visible) edge.
12919  makeshellface(subfaces, &newsh);
12920  setshvertices(newsh, pb, pa, insertpt);
12921  setshellmark(newsh, shellmark(*searchsh));
12922  if (checkconstraints) {
12923  //area = areabound(*searchsh);
12924  setareabound(newsh, areabound(*searchsh));
12925  }
12926  if (useinsertradius) {
12927  setfacetindex(newsh, getfacetindex(*searchsh));
12928  }
12929  // Connect the new subface to the bottom subfaces.
12930  sbond1(newsh, *searchsh);
12931  sbond1(*searchsh, newsh);
12932  // Connect the new subface to its right-adjacent subface.
12933  if (casin.sh != NULL) {
12934  senext(newsh, casout);
12935  sbond1(casout, casin);
12936  sbond1(casin, casout);
12937  }
12938  // The left-adjacent subface has not been created yet.
12939  senext2(newsh, casin);
12940  // Add the new face into list (inside the B-W cavity).
12941  smarktest(newsh);
12942  caveshlist->newindex((void **) &parysh);
12943  *parysh = newsh;
12944  // Move to the convex hull edge at the left of 'searchsh'.
12945  neighsh = *searchsh;
12946  while (1) {
12947  senextself(neighsh);
12948  spivot(neighsh, casout);
12949  if (casout.sh == NULL) {
12950  *searchsh = neighsh;
12951  break;
12952  }
12953  if (sorg(casout) != sdest(neighsh)) sesymself(casout);
12954  neighsh = casout;
12955  }
12956  // A convex hull edge. Is it visible by p.
12957  pa = sorg(*searchsh);
12958  pb = sdest(*searchsh);
12959  ori = orient3d(pa, pb, dummypoint, insertpt);
12960  // Finish the process if p is not visible by the hull edge.
12961  if (ori >= 0) break;
12962  }
12963  } else if (loc == INSTAR) {
12964  // Under this case, the sub-cavity sC(p) has already been formed in
12965  // insertvertex().
12966  }
12967 
12968  // Form the Bowyer-Watson cavity sC(p).
12969  for (i = 0; i < caveshlist->objects; i++) {
12970  cavesh = * (face *) fastlookup(caveshlist, i);
12971  for (j = 0; j < 3; j++) {
12972  if (!isshsubseg(cavesh)) {
12973  spivot(cavesh, neighsh);
12974  if (neighsh.sh != NULL) {
12975  // The adjacent face exists.
12976  if (!smarktested(neighsh)) {
12977  if (bowywat) {
12978  if (loc == INSTAR) { // if (bowywat > 2) {
12979  // It must be a boundary edge.
12980  sign = 1;
12981  } else {
12982  // Check if this subface is connected to adjacent tet(s).
12983  if (!isshtet(neighsh)) {
12984  // Check if the subface is non-Delaunay wrt. the new pt.
12985  sign = incircle3d(sorg(neighsh), sdest(neighsh),
12986  sapex(neighsh), insertpt);
12987  } else {
12988  // It is connected to an adjacent tet. A boundary edge.
12989  sign = 1;
12990  }
12991  }
12992  if (sign < 0) {
12993  // Add the adjacent face in list (in B-W cavity).
12994  smarktest(neighsh);
12995  caveshlist->newindex((void **) &parysh);
12996  *parysh = neighsh;
12997  }
12998  } else {
12999  sign = 1; // A boundary edge.
13000  }
13001  } else {
13002  sign = -1; // Not a boundary edge.
13003  }
13004  } else {
13005  // No adjacent face. It is a hull edge.
13006  if (loc == OUTSIDE) {
13007  // It is a boundary edge if it does not contain p.
13008  if ((sorg(cavesh) == insertpt) || (sdest(cavesh) == insertpt)) {
13009  sign = -1; // Not a boundary edge.
13010  } else {
13011  sign = 1; // A boundary edge.
13012  }
13013  } else {
13014  sign = 1; // A boundary edge.
13015  }
13016  }
13017  } else {
13018  // Do not across a segment. It is a boundary edge.
13019  sign = 1;
13020  }
13021  if (sign >= 0) {
13022  // Add a boundary edge.
13023  caveshbdlist->newindex((void **) &parysh);
13024  *parysh = cavesh;
13025  }
13026  senextself(cavesh);
13027  } // j
13028  } // i
13029 
13030 
13031  // Creating new subfaces.
13032  for (i = 0; i < caveshbdlist->objects; i++) {
13033  parysh = (face *) fastlookup(caveshbdlist, i);
13034  sspivot(*parysh, checkseg);
13035  if ((parysh->shver & 01) != 0) sesymself(*parysh);
13036  pa = sorg(*parysh);
13037  pb = sdest(*parysh);
13038  // Create a new subface.
13039  makeshellface(subfaces, &newsh);
13040  setshvertices(newsh, pa, pb, insertpt);
13041  setshellmark(newsh, shellmark(*parysh));
13042  if (checkconstraints) {
13043  //area = areabound(*parysh);
13044  setareabound(newsh, areabound(*parysh));
13045  }
13046  if (useinsertradius) {
13047  setfacetindex(newsh, getfacetindex(*parysh));
13048  }
13049  // Update the point-to-subface map.
13050  if (pointtype(pa) == FREEFACETVERTEX) {
13051  setpoint2sh(pa, sencode(newsh));
13052  }
13053  if (pointtype(pb) == FREEFACETVERTEX) {
13054  setpoint2sh(pb, sencode(newsh));
13055  }
13056  // Connect newsh to outer subfaces.
13057  spivot(*parysh, casout);
13058  if (casout.sh != NULL) {
13059  casin = casout;
13060  if (checkseg.sh != NULL) {
13061  // Make sure that newsh has the right ori at this segment.
13062  checkseg.shver = 0;
13063  if (sorg(newsh) != sorg(checkseg)) {
13064  sesymself(newsh);
13065  sesymself(*parysh); // This side should also be inverse.
13066  }
13067  spivot(casin, neighsh);
13068  while (neighsh.sh != parysh->sh) {
13069  casin = neighsh;
13070  spivot(casin, neighsh);
13071  }
13072  }
13073  sbond1(newsh, casout);
13074  sbond1(casin, newsh);
13075  }
13076  if (checkseg.sh != NULL) {
13077  ssbond(newsh, checkseg);
13078  }
13079  // Connect oldsh <== newsh (for connecting adjacent new subfaces).
13080  // *parysh and newsh point to the same edge and the same ori.
13081  sbond1(*parysh, newsh);
13082  }
13083 
13084  if (newsh.sh != NULL) {
13085  // Set a handle for searching.
13086  recentsh = newsh;
13087  }
13088 
13089  // Update the point-to-subface map.
13090  if (pointtype(insertpt) == FREEFACETVERTEX) {
13091  setpoint2sh(insertpt, sencode(newsh));
13092  }
13093 
13094  // Connect adjacent new subfaces together.
13095  for (i = 0; i < caveshbdlist->objects; i++) {
13096  // Get an old subface at edge [a, b].
13097  parysh = (face *) fastlookup(caveshbdlist, i);
13098  spivot(*parysh, newsh); // The new subface [a, b, p].
13099  senextself(newsh); // At edge [b, p].
13100  spivot(newsh, neighsh);
13101  if (neighsh.sh == NULL) {
13102  // Find the adjacent new subface at edge [b, p].
13103  pb = sdest(*parysh);
13104  neighsh = *parysh;
13105  while (1) {
13106  senextself(neighsh);
13107  spivotself(neighsh);
13108  if (neighsh.sh == NULL) break;
13109  if (!smarktested(neighsh)) break;
13110  if (sdest(neighsh) != pb) sesymself(neighsh);
13111  }
13112  if (neighsh.sh != NULL) {
13113  // Now 'neighsh' is a new subface at edge [b, #].
13114  if (sorg(neighsh) != pb) sesymself(neighsh);
13115  senext2self(neighsh); // Go to the open edge [p, b].
13116  sbond(newsh, neighsh);
13117  }
13118  }
13119  spivot(*parysh, newsh); // The new subface [a, b, p].
13120  senext2self(newsh); // At edge [p, a].
13121  spivot(newsh, neighsh);
13122  if (neighsh.sh == NULL) {
13123  // Find the adjacent new subface at edge [p, a].
13124  pa = sorg(*parysh);
13125  neighsh = *parysh;
13126  while (1) {
13127  senext2self(neighsh);
13128  spivotself(neighsh);
13129  if (neighsh.sh == NULL) break;
13130  if (!smarktested(neighsh)) break;
13131  if (sorg(neighsh) != pa) sesymself(neighsh);
13132  }
13133  if (neighsh.sh != NULL) {
13134  // Now 'neighsh' is a new subface at edge [#, a].
13135  if (sdest(neighsh) != pa) sesymself(neighsh);
13136  senextself(neighsh); // Go to the open edge [a, p].
13137  sbond(newsh, neighsh);
13138  }
13139  }
13140  }
13141 
13142  if ((loc == ONEDGE) || ((splitseg != NULL) && (splitseg->sh != NULL))
13143  || (cavesegshlist->objects > 0l)) {
13144  // An edge is being split. We distinguish two cases:
13145  // (1) the edge is not on the boundary of the cavity;
13146  // (2) the edge is on the boundary of the cavity.
13147  // In case (2), the edge is either a segment or a hull edge. There are
13148  // degenerated new faces in the cavity. They must be removed.
13149  face aseg, bseg, aoutseg, boutseg;
13150 
13151  for (i = 0; i < cavesegshlist->objects; i++) {
13152  // Get the saved old subface.
13153  parysh = (face *) fastlookup(cavesegshlist, i);
13154  // Get a possible new degenerated subface.
13155  spivot(*parysh, cavesh);
13156  if (sapex(cavesh) == insertpt) {
13157  // Found a degenerated new subface, i.e., case (2).
13158  if (cavesegshlist->objects > 1) {
13159  // There are more than one subface share at this edge.
13160  j = (i + 1) % (int) cavesegshlist->objects;
13161  parysh = (face *) fastlookup(cavesegshlist, j);
13162  spivot(*parysh, neighsh);
13163  // Adjust cavesh and neighsh both at edge a->b, and has p as apex.
13164  if (sorg(neighsh) != sorg(cavesh)) {
13165  sesymself(neighsh);
13166  }
13167  // Connect adjacent faces at two other edges of cavesh and neighsh.
13168  // As a result, the two degenerated new faces are squeezed from the
13169  // new triangulation of the cavity. Note that the squeezed faces
13170  // still hold the adjacent informations which will be used in
13171  // re-connecting subsegments (if they exist).
13172  for (j = 0; j < 2; j++) {
13173  senextself(cavesh);
13174  senextself(neighsh);
13175  spivot(cavesh, newsh);
13176  spivot(neighsh, casout);
13177  sbond1(newsh, casout); // newsh <- casout.
13178  }
13179  } else {
13180  // There is only one subface containing this edge [a,b]. Squeeze the
13181  // degenerated new face [a,b,c] by disconnecting it from its two
13182  // adjacent subfaces at edges [b,c] and [c,a]. Note that the face
13183  // [a,b,c] still hold the connection to them.
13184  for (j = 0; j < 2; j++) {
13185  senextself(cavesh);
13186  spivot(cavesh, newsh);
13187  sdissolve(newsh);
13188  }
13189  }
13190  //recentsh = newsh;
13191  // Update the point-to-subface map.
13192  if (pointtype(insertpt) == FREEFACETVERTEX) {
13193  setpoint2sh(insertpt, sencode(newsh));
13194  }
13195  }
13196  }
13197 
13198  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
13199  if (loc != INSTAR) { // if (bowywat < 3) {
13200  smarktest(*splitseg); // Mark it as being processed.
13201  }
13202 
13203  aseg = *splitseg;
13204  pa = sorg(*splitseg);
13205  pb = sdest(*splitseg);
13206 
13207  // Insert the new point p.
13208  makeshellface(subsegs, &aseg);
13209  makeshellface(subsegs, &bseg);
13210 
13211  setshvertices(aseg, pa, insertpt, NULL);
13212  setshvertices(bseg, insertpt, pb, NULL);
13213  setshellmark(aseg, shellmark(*splitseg));
13214  setshellmark(bseg, shellmark(*splitseg));
13215  if (checkconstraints) {
13216  setareabound(aseg, areabound(*splitseg));
13217  setareabound(bseg, areabound(*splitseg));
13218  }
13219  if (useinsertradius) {
13220  setfacetindex(aseg, getfacetindex(*splitseg));
13221  setfacetindex(bseg, getfacetindex(*splitseg));
13222  }
13223 
13224  // Connect [#, a]<->[a, p].
13225  senext2(*splitseg, boutseg); // Temporarily use boutseg.
13226  spivotself(boutseg);
13227  if (boutseg.sh != NULL) {
13228  senext2(aseg, aoutseg);
13229  sbond(boutseg, aoutseg);
13230  }
13231  // Connect [p, b]<->[b, #].
13232  senext(*splitseg, aoutseg);
13233  spivotself(aoutseg);
13234  if (aoutseg.sh != NULL) {
13235  senext(bseg, boutseg);
13236  sbond(boutseg, aoutseg);
13237  }
13238  // Connect [a, p] <-> [p, b].
13239  senext(aseg, aoutseg);
13240  senext2(bseg, boutseg);
13241  sbond(aoutseg, boutseg);
13242 
13243  // Connect subsegs [a, p] and [p, b] to adjacent new subfaces.
13244  // Although the degenerated new faces have been squeezed. They still
13245  // hold the connections to the actual new faces.
13246  for (i = 0; i < cavesegshlist->objects; i++) {
13247  parysh = (face *) fastlookup(cavesegshlist, i);
13248  spivot(*parysh, neighsh);
13249  // neighsh is a degenerated new face.
13250  if (sorg(neighsh) != pa) {
13251  sesymself(neighsh);
13252  }
13253  senext2(neighsh, newsh);
13254  spivotself(newsh); // The edge [p, a] in newsh
13255  ssbond(newsh, aseg);
13256  senext(neighsh, newsh);
13257  spivotself(newsh); // The edge [b, p] in newsh
13258  ssbond(newsh, bseg);
13259  }
13260 
13261 
13262  // Let the point remember the segment it lies on.
13263  if (pointtype(insertpt) == FREESEGVERTEX) {
13264  setpoint2sh(insertpt, sencode(aseg));
13265  }
13266  // Update the point-to-seg map.
13267  if (pointtype(pa) == FREESEGVERTEX) {
13268  setpoint2sh(pa, sencode(aseg));
13269  }
13270  if (pointtype(pb) == FREESEGVERTEX) {
13271  setpoint2sh(pb, sencode(bseg));
13272  }
13273  } // if ((splitseg != NULL) && (splitseg->sh != NULL))
13274 
13275  // Delete all degenerated new faces.
13276  for (i = 0; i < cavesegshlist->objects; i++) {
13277  parysh = (face *) fastlookup(cavesegshlist, i);
13278  spivotself(*parysh);
13279  if (sapex(*parysh) == insertpt) {
13280  shellfacedealloc(subfaces, parysh->sh);
13281  }
13282  }
13283  cavesegshlist->restart();
13284 
13285  if ((splitseg != NULL) && (splitseg->sh != NULL)) {
13286  // Return the two new subsegments (for further process).
13287  // Re-use 'cavesegshlist'.
13288  cavesegshlist->newindex((void **) &parysh);
13289  *parysh = aseg;
13290  cavesegshlist->newindex((void **) &parysh);
13291  *parysh = bseg;
13292  }
13293  } // if (loc == ONEDGE)
13294 
13295 
13296  return (int) loc;
13297 }
13298 
13300 // //
13301 // sremovevertex() Remove a vertex from the surface mesh. //
13302 // //
13303 // 'delpt' (p) is the vertex to be removed. If 'parentseg' is not NULL, p is //
13304 // a segment vertex, and the origin of 'parentseg' is p. Otherwise, p is a //
13305 // facet vertex, and the origin of 'parentsh' is p. //
13306 // //
13307 // Within each facet, we first use a sequence of 2-to-2 flips to flip any //
13308 // edge at p, finally use a 3-to-1 flip to remove p. //
13309 // //
13310 // All new created subfaces are returned in the global array 'caveshbdlist'. //
13311 // The new segment (when p is on segment) is returned in 'parentseg'. //
13312 // //
13313 // If 'lawson' > 0, the Lawson flip algorithm is used to recover Delaunay- //
13314 // ness after p is removed. //
13315 // //
13317 
13318 int tetgenmesh::sremovevertex(point delpt, face* parentsh, face* parentseg,
13319  int lawson)
13320 {
13321  face flipfaces[4], spinsh, *parysh;
13322  point pa, pb, pc, pd;
13323  REAL ori1, ori2;
13324  int it, i, j;
13325 
13326  if (parentseg != NULL) {
13327  // 'delpt' (p) should be a Steiner point inserted in a segment [a,b],
13328  // where 'parentseg' should be [p,b]. Find the segment [a,p].
13329  face startsh, neighsh, nextsh;
13330  face abseg, prevseg, checkseg;
13331  face adjseg1, adjseg2;
13332  face fakesh;
13333  senext2(*parentseg, prevseg);
13334  spivotself(prevseg);
13335  prevseg.shver = 0;
13336  // Restore the original segment [a,b].
13337  pa = sorg(prevseg);
13338  pb = sdest(*parentseg);
13339  if (b->verbose > 2) {
13340  printf(" Remove vertex %d from segment [%d, %d].\n",
13341  pointmark(delpt), pointmark(pa), pointmark(pb));
13342  }
13343  makeshellface(subsegs, &abseg);
13344  setshvertices(abseg, pa, pb, NULL);
13345  setshellmark(abseg, shellmark(*parentseg));
13346  if (checkconstraints) {
13347  setareabound(abseg, areabound(*parentseg));
13348  }
13349  if (useinsertradius) {
13350  setfacetindex(abseg, getfacetindex(*parentseg));
13351  }
13352  // Connect [#, a]<->[a, b].
13353  senext2(prevseg, adjseg1);
13354  spivotself(adjseg1);
13355  if (adjseg1.sh != NULL) {
13356  adjseg1.shver = 0;
13357  senextself(adjseg1);
13358  senext2(abseg, adjseg2);
13359  sbond(adjseg1, adjseg2);
13360  }
13361  // Connect [a, b]<->[b, #].
13362  senext(*parentseg, adjseg1);
13363  spivotself(adjseg1);
13364  if (adjseg1.sh != NULL) {
13365  adjseg1.shver = 0;
13366  senext2self(adjseg1);
13367  senext(abseg, adjseg2);
13368  sbond(adjseg1, adjseg2);
13369  }
13370  // Update the point-to-segment map.
13371  setpoint2sh(pa, sencode(abseg));
13372  setpoint2sh(pb, sencode(abseg));
13373 
13374  // Get the faces in face ring at segment [p, b].
13375  // Re-use array 'caveshlist'.
13376  spivot(*parentseg, *parentsh);
13377  if (parentsh->sh != NULL) {
13378  spinsh = *parentsh;
13379  while (1) {
13380  // Save this face in list.
13381  caveshlist->newindex((void **) &parysh);
13382  *parysh = spinsh;
13383  // Go to the next face in the ring.
13384  spivotself(spinsh);
13385  if (spinsh.sh == NULL) {
13386  break; // It is possible there is only one facet.
13387  }
13388  if (spinsh.sh == parentsh->sh) break;
13389  }
13390  }
13391 
13392  // Create the face ring of the new segment [a,b]. Each face in the ring
13393  // is [a,b,p] (degenerated!). It will be removed (automatically).
13394  for (i = 0; i < caveshlist->objects; i++) {
13395  parysh = (face *) fastlookup(caveshlist, i);
13396  startsh = *parysh;
13397  if (sorg(startsh) != delpt) {
13398  sesymself(startsh);
13399  }
13400  // startsh is [p, b, #1], find the subface [a, p, #2].
13401  neighsh = startsh;
13402  while (1) {
13403  senext2self(neighsh);
13404  sspivot(neighsh, checkseg);
13405  if (checkseg.sh != NULL) {
13406  // It must be the segment [a, p].
13407  break;
13408  }
13409  spivotself(neighsh);
13410  if (sorg(neighsh) != delpt) sesymself(neighsh);
13411  }
13412  // Now neighsh is [a, p, #2].
13413  if (neighsh.sh != startsh.sh) {
13414  // Detach the two subsegments [a,p] and [p,b] from subfaces.
13415  ssdissolve(startsh);
13416  ssdissolve(neighsh);
13417  // Create a degenerated subface [a,b,p]. It is used to: (1) hold the
13418  // new segment [a,b]; (2) connect to the two adjacent subfaces
13419  // [p,b,#] and [a,p,#].
13420  makeshellface(subfaces, &fakesh);
13421  setshvertices(fakesh, pa, pb, delpt);
13422  setshellmark(fakesh, shellmark(startsh));
13423  // Connect fakesh to the segment [a,b].
13424  ssbond(fakesh, abseg);
13425  // Connect fakesh to adjacent subfaces: [p,b,#1] and [a,p,#2].
13426  senext(fakesh, nextsh);
13427  sbond(nextsh, startsh);
13428  senext2(fakesh, nextsh);
13429  sbond(nextsh, neighsh);
13430  smarktest(fakesh); // Mark it as faked.
13431  } else {
13432  // Special case. There exists already a degenerated face [a,b,p]!
13433  // There is no need to create a faked subface here.
13434  senext2self(neighsh); // [a,b,p]
13435  // Since we will re-connect the face ring using the faked subfaces.
13436  // We put the adjacent face of [a,b,p] to the list.
13437  spivot(neighsh, startsh); // The original adjacent subface.
13438  if (sorg(startsh) != pa) sesymself(startsh);
13439  sdissolve(startsh);
13440  // Connect fakesh to the segment [a,b].
13441  ssbond(startsh, abseg);
13442  fakesh = startsh; // Do not mark it!
13443  // Delete the degenerated subface.
13444  shellfacedealloc(subfaces, neighsh.sh);
13445  }
13446  // Save the fakesh in list (for re-creating the face ring).
13447  cavesegshlist->newindex((void **) &parysh);
13448  *parysh = fakesh;
13449  } // i
13450  caveshlist->restart();
13451 
13452  // Re-create the face ring.
13453  if (cavesegshlist->objects > 1) {
13454  for (i = 0; i < cavesegshlist->objects; i++) {
13455  parysh = (face *) fastlookup(cavesegshlist, i);
13456  fakesh = *parysh;
13457  // Get the next face in the ring.
13458  j = (i + 1) % cavesegshlist->objects;
13459  parysh = (face *) fastlookup(cavesegshlist, j);
13460  nextsh = *parysh;
13461  sbond1(fakesh, nextsh);
13462  }
13463  }
13464 
13465  // Delete the two subsegments containing p.
13466  shellfacedealloc(subsegs, parentseg->sh);
13467  shellfacedealloc(subsegs, prevseg.sh);
13468  // Return the new segment.
13469  *parentseg = abseg;
13470  } else {
13471  // p is inside the surface.
13472  if (b->verbose > 2) {
13473  printf(" Remove vertex %d from surface.\n", pointmark(delpt));
13474  }
13475  // Let 'delpt' be its apex.
13476  senextself(*parentsh);
13477  // For unifying the code, we add parentsh to list.
13478  cavesegshlist->newindex((void **) &parysh);
13479  *parysh = *parentsh;
13480  }
13481 
13482  // Remove the point (p).
13483 
13484  for (it = 0; it < cavesegshlist->objects; it++) {
13485  parentsh = (face *) fastlookup(cavesegshlist, it); // [a,b,p]
13486  senextself(*parentsh); // [b,p,a].
13487  spivotself(*parentsh);
13488  if (sorg(*parentsh) != delpt) sesymself(*parentsh);
13489  // now parentsh is [p,b,#].
13490  if (sorg(*parentsh) != delpt) {
13491  // The vertex has already been removed in above special case.
13492  continue;
13493  }
13494 
13495  while (1) {
13496  // Initialize the flip edge list. Re-use 'caveshlist'.
13497  spinsh = *parentsh; // [p, b, #]
13498  while (1) {
13499  caveshlist->newindex((void **) &parysh);
13500  *parysh = spinsh;
13501  senext2self(spinsh);
13502  spivotself(spinsh);
13503  if (spinsh.sh == parentsh->sh) break;
13504  if (sorg(spinsh) != delpt) sesymself(spinsh);
13505  } // while (1)
13506 
13507  if (caveshlist->objects == 3) {
13508  // Delete the point by a 3-to-1 flip.
13509  for (i = 0; i < 3; i++) {
13510  parysh = (face *) fastlookup(caveshlist, i);
13511  flipfaces[i] = *parysh;
13512  }
13513  flip31(flipfaces, lawson);
13514  for (i = 0; i < 3; i++) {
13515  shellfacedealloc(subfaces, flipfaces[i].sh);
13516  }
13517  caveshlist->restart();
13518  // Save the new subface.
13519  caveshbdlist->newindex((void **) &parysh);
13520  *parysh = flipfaces[3];
13521  // The vertex is removed.
13522  break;
13523  }
13524 
13525  // Search an edge to flip.
13526  for (i = 0; i < caveshlist->objects; i++) {
13527  parysh = (face *) fastlookup(caveshlist, i);
13528  flipfaces[0] = *parysh;
13529  spivot(flipfaces[0], flipfaces[1]);
13530  if (sorg(flipfaces[0]) != sdest(flipfaces[1]))
13531  sesymself(flipfaces[1]);
13532  // Skip this edge if it belongs to a faked subface.
13533  if (!smarktested(flipfaces[0]) && !smarktested(flipfaces[1])) {
13534  pa = sorg(flipfaces[0]);
13535  pb = sdest(flipfaces[0]);
13536  pc = sapex(flipfaces[0]);
13537  pd = sapex(flipfaces[1]);
13538  calculateabovepoint4(pa, pb, pc, pd);
13539  // Check if a 2-to-2 flip is possible.
13540  ori1 = orient3d(pc, pd, dummypoint, pa);
13541  ori2 = orient3d(pc, pd, dummypoint, pb);
13542  if (ori1 * ori2 < 0) {
13543  // A 2-to-2 flip is found.
13544  flip22(flipfaces, lawson, 0);
13545  // The i-th edge is flipped. The i-th and (i-1)-th subfaces are
13546  // changed. The 'flipfaces[1]' contains p as its apex.
13547  senext2(flipfaces[1], *parentsh);
13548  // Save the new subface.
13549  caveshbdlist->newindex((void **) &parysh);
13550  *parysh = flipfaces[0];
13551  break;
13552  }
13553  } //
13554  } // i
13555 
13556  if (i == caveshlist->objects) {
13557  // Do a flip22 and a flip31 to remove p.
13558  parysh = (face *) fastlookup(caveshlist, 0);
13559  flipfaces[0] = *parysh;
13560  spivot(flipfaces[0], flipfaces[1]);
13561  if (sorg(flipfaces[0]) != sdest(flipfaces[1])) {
13562  sesymself(flipfaces[1]);
13563  }
13564  flip22(flipfaces, lawson, 0);
13565  senext2(flipfaces[1], *parentsh);
13566  // Save the new subface.
13567  caveshbdlist->newindex((void **) &parysh);
13568  *parysh = flipfaces[0];
13569  }
13570 
13571  // The edge list at p are changed.
13572  caveshlist->restart();
13573  } // while (1)
13574 
13575  } // it
13576 
13577  cavesegshlist->restart();
13578 
13579  if (b->verbose > 2) {
13580  printf(" Created %ld new subfaces.\n", caveshbdlist->objects);
13581  }
13582 
13583 
13584  if (lawson) {
13585  lawsonflip();
13586  }
13587 
13588  return 0;
13589 }
13590 
13592 // //
13593 // slocate() Locate a point in a surface triangulation. //
13594 // //
13595 // Staring the search from 'searchsh'(it should not be NULL). Perform a line //
13596 // walk search for a subface containing the point (p). //
13597 // //
13598 // If 'aflag' is set, the 'dummypoint' is pre-calculated so that it lies //
13599 // above the 'searchsh' in its current orientation. The test if c is CCW to //
13600 // the line a->b can be done by the test if c is below the oriented plane //
13601 // a->b->dummypoint. //
13602 // //
13603 // If 'cflag' is not TRUE, the triangulation may not be convex. Stop search //
13604 // when a segment is met and return OUTSIDE. //
13605 // //
13606 // If 'rflag' (rounding) is set, after the location of the point is found, //
13607 // either ONEDGE or ONFACE, round the result using an epsilon. //
13608 // //
13609 // The returned value indicates the following cases: //
13610 // - ONVERTEX, p is the origin of 'searchsh'. //
13611 // - ONEDGE, p lies on the edge of 'searchsh'. //
13612 // - ONFACE, p lies in the interior of 'searchsh'. //
13613 // - OUTSIDE, p lies outside of the triangulation, p is on the left-hand //
13614 // side of the edge 'searchsh'(s), i.e., org(s), dest(s), p are CW. //
13615 // //
13617 
13618 enum tetgenmesh::locateresult tetgenmesh::slocate(point searchpt,
13619  face* searchsh, int aflag, int cflag, int rflag)
13620 {
13621  face neighsh;
13622  point pa, pb, pc;
13623  enum locateresult loc;
13624  enum {MOVE_BC, MOVE_CA} nextmove;
13625  REAL ori, ori_bc, ori_ca;
13626  int i;
13627 
13628  pa = sorg(*searchsh);
13629  pb = sdest(*searchsh);
13630  pc = sapex(*searchsh);
13631 
13632  if (!aflag) {
13633  // No above point is given. Calculate an above point for this facet.
13634  calculateabovepoint4(pa, pb, pc, searchpt);
13635  }
13636 
13637  // 'dummypoint' is given. Make sure it is above [a,b,c]
13638  ori = orient3d(pa, pb, pc, dummypoint);
13639  if (ori > 0) {
13640  sesymself(*searchsh); // Reverse the face orientation.
13641  } else if (ori == 0.0) {
13642  // This case should not happen theoretically. But...
13643  return UNKNOWN;
13644  }
13645 
13646  // Find an edge of the face s.t. p lies on its right-hand side (CCW).
13647  for (i = 0; i < 3; i++) {
13648  pa = sorg(*searchsh);
13649  pb = sdest(*searchsh);
13650  ori = orient3d(pa, pb, dummypoint, searchpt);
13651  if (ori > 0) break;
13652  senextself(*searchsh);
13653  }
13654  if (i == 3) {
13655  return UNKNOWN;
13656  }
13657 
13658  pc = sapex(*searchsh);
13659 
13660  if (pc == searchpt) {
13661  senext2self(*searchsh);
13662  return ONVERTEX;
13663  }
13664 
13665  while (1) {
13666 
13667  ori_bc = orient3d(pb, pc, dummypoint, searchpt);
13668  ori_ca = orient3d(pc, pa, dummypoint, searchpt);
13669 
13670  if (ori_bc < 0) {
13671  if (ori_ca < 0) { // (--)
13672  // Any of the edges is a viable move.
13673  if (randomnation(2)) {
13674  nextmove = MOVE_CA;
13675  } else {
13676  nextmove = MOVE_BC;
13677  }
13678  } else { // (-#)
13679  // Edge [b, c] is viable.
13680  nextmove = MOVE_BC;
13681  }
13682  } else {
13683  if (ori_ca < 0) { // (#-)
13684  // Edge [c, a] is viable.
13685  nextmove = MOVE_CA;
13686  } else {
13687  if (ori_bc > 0) {
13688  if (ori_ca > 0) { // (++)
13689  loc = ONFACE; // Inside [a, b, c].
13690  break;
13691  } else { // (+0)
13692  senext2self(*searchsh); // On edge [c, a].
13693  loc = ONEDGE;
13694  break;
13695  }
13696  } else { // ori_bc == 0
13697  if (ori_ca > 0) { // (0+)
13698  senextself(*searchsh); // On edge [b, c].
13699  loc = ONEDGE;
13700  break;
13701  } else { // (00)
13702  // p is coincident with vertex c.
13703  senext2self(*searchsh);
13704  return ONVERTEX;
13705  }
13706  }
13707  }
13708  }
13709 
13710  // Move to the next face.
13711  if (nextmove == MOVE_BC) {
13712  senextself(*searchsh);
13713  } else {
13714  senext2self(*searchsh);
13715  }
13716  if (!cflag) {
13717  // NON-convex case. Check if we will cross a boundary.
13718  if (isshsubseg(*searchsh)) {
13719  return ENCSEGMENT;
13720  }
13721  }
13722  spivot(*searchsh, neighsh);
13723  if (neighsh.sh == NULL) {
13724  return OUTSIDE; // A hull edge.
13725  }
13726  // Adjust the edge orientation.
13727  if (sorg(neighsh) != sdest(*searchsh)) {
13728  sesymself(neighsh);
13729  }
13730 
13731  // Update the newly discovered face and its endpoints.
13732  *searchsh = neighsh;
13733  pa = sorg(*searchsh);
13734  pb = sdest(*searchsh);
13735  pc = sapex(*searchsh);
13736 
13737  if (pc == searchpt) {
13738  senext2self(*searchsh);
13739  return ONVERTEX;
13740  }
13741 
13742  } // while (1)
13743 
13744  // assert(loc == ONFACE || loc == ONEDGE);
13745 
13746 
13747  if (rflag) {
13748  // Round the locate result before return.
13749  REAL n[3], area_abc, area_abp, area_bcp, area_cap;
13750 
13751  pa = sorg(*searchsh);
13752  pb = sdest(*searchsh);
13753  pc = sapex(*searchsh);
13754 
13755  facenormal(pa, pb, pc, n, 1, NULL);
13756  area_abc = sqrt(dot(n, n));
13757 
13758  facenormal(pb, pc, searchpt, n, 1, NULL);
13759  area_bcp = sqrt(dot(n, n));
13760  if ((area_bcp / area_abc) < b->epsilon) {
13761  area_bcp = 0; // Rounding.
13762  }
13763 
13764  facenormal(pc, pa, searchpt, n, 1, NULL);
13765  area_cap = sqrt(dot(n, n));
13766  if ((area_cap / area_abc) < b->epsilon) {
13767  area_cap = 0; // Rounding
13768  }
13769 
13770  if ((loc == ONFACE) || (loc == OUTSIDE)) {
13771  facenormal(pa, pb, searchpt, n, 1, NULL);
13772  area_abp = sqrt(dot(n, n));
13773  if ((area_abp / area_abc) < b->epsilon) {
13774  area_abp = 0; // Rounding
13775  }
13776  } else { // loc == ONEDGE
13777  area_abp = 0;
13778  }
13779 
13780  if (area_abp == 0) {
13781  if (area_bcp == 0) {
13782  senextself(*searchsh);
13783  loc = ONVERTEX; // p is close to b.
13784  } else {
13785  if (area_cap == 0) {
13786  loc = ONVERTEX; // p is close to a.
13787  } else {
13788  loc = ONEDGE; // p is on edge [a,b].
13789  }
13790  }
13791  } else if (area_bcp == 0) {
13792  if (area_cap == 0) {
13793  senext2self(*searchsh);
13794  loc = ONVERTEX; // p is close to c.
13795  } else {
13796  senextself(*searchsh);
13797  loc = ONEDGE; // p is on edge [b,c].
13798  }
13799  } else if (area_cap == 0) {
13800  senext2self(*searchsh);
13801  loc = ONEDGE; // p is on edge [c,a].
13802  } else {
13803  loc = ONFACE; // p is on face [a,b,c].
13804  }
13805  } // if (rflag)
13806 
13807  return loc;
13808 }
13809 
13811 // //
13812 // sscoutsegment() Look for a segment in the surface triangulation. //
13813 // //
13814 // The segment is given by the origin of 'searchsh' and 'endpt'. //
13815 // //
13816 // If an edge in T is found matching this segment, the segment is "locked" //
13817 // in T at the edge. Otherwise, flip the first edge in T that the segment //
13818 // crosses. Continue the search from the flipped face. //
13819 // //
13820 // This routine uses 'orisent3d' to determine the search direction. It uses //
13821 // 'dummypoint' as the 'lifted point' in 3d, and it assumes that it (dummy- //
13822 // point) lies above the 'searchsh' (w.r.t the Right-hand rule). //
13823 // //
13825 
13826 enum tetgenmesh::interresult tetgenmesh::sscoutsegment(face *searchsh,
13827  point endpt, int insertsegflag, int reporterrorflag, int chkencflag)
13828 {
13829  face flipshs[2], neighsh;
13830  point startpt, pa, pb, pc, pd;
13831  enum interresult dir;
13832  enum {MOVE_AB, MOVE_CA} nextmove;
13833  REAL ori_ab, ori_ca, len;
13834 
13835  pc = NULL; // Avoid warnings from MSVC
13836  // The origin of 'searchsh' is fixed.
13837  startpt = sorg(*searchsh);
13838  nextmove = MOVE_AB; // Avoid compiler warning.
13839 
13840  if (b->verbose > 2) {
13841  printf(" Scout segment (%d, %d).\n", pointmark(startpt),
13842  pointmark(endpt));
13843  }
13844  len = distance(startpt, endpt);
13845 
13846  // Search an edge in 'searchsh' on the path of this segment.
13847  while (1) {
13848 
13849  pb = sdest(*searchsh);
13850  if (pb == endpt) {
13851  dir = SHAREEDGE; // Found!
13852  break;
13853  }
13854 
13855  pc = sapex(*searchsh);
13856  if (pc == endpt) {
13857  senext2self(*searchsh);
13858  sesymself(*searchsh);
13859  dir = SHAREEDGE; // Found!
13860  break;
13861  }
13862 
13863 
13864  // Round the results.
13865  if ((sqrt(triarea(startpt, pb, endpt)) / len) < b->epsilon) {
13866  ori_ab = 0.0;
13867  } else {
13868  ori_ab = orient3d(startpt, pb, dummypoint, endpt);
13869  }
13870  if ((sqrt(triarea(pc, startpt, endpt)) / len) < b->epsilon) {
13871  ori_ca = 0.0;
13872  } else {
13873  ori_ca = orient3d(pc, startpt, dummypoint, endpt);
13874  }
13875 
13876  if (ori_ab < 0) {
13877  if (ori_ca < 0) { // (--)
13878  // Both sides are viable moves.
13879  if (randomnation(2)) {
13880  nextmove = MOVE_CA;
13881  } else {
13882  nextmove = MOVE_AB;
13883  }
13884  } else { // (-#)
13885  nextmove = MOVE_AB;
13886  }
13887  } else {
13888  if (ori_ca < 0) { // (#-)
13889  nextmove = MOVE_CA;
13890  } else {
13891  if (ori_ab > 0) {
13892  if (ori_ca > 0) { // (++)
13893  // The segment intersects with edge [b, c].
13894  dir = ACROSSEDGE;
13895  break;
13896  } else { // (+0)
13897  // The segment collinear with edge [c, a].
13898  senext2self(*searchsh);
13899  sesymself(*searchsh);
13900  dir = ACROSSVERT;
13901  break;
13902  }
13903  } else {
13904  if (ori_ca > 0) { // (0+)
13905  // The segment is collinear with edge [a, b].
13906  dir = ACROSSVERT;
13907  break;
13908  } else { // (00)
13909  // startpt == endpt. Not possible.
13910  terminatetetgen(this, 2);
13911  }
13912  }
13913  }
13914  }
13915 
13916  // Move 'searchsh' to the next face, keep the origin unchanged.
13917  if (nextmove == MOVE_AB) {
13918  if (chkencflag) {
13919  // Do not cross boundary.
13920  if (isshsubseg(*searchsh)) {
13921  return ACROSSEDGE; // ACROSS_SEG
13922  }
13923  }
13924  spivot(*searchsh, neighsh);
13925  if (neighsh.sh != NULL) {
13926  if (sorg(neighsh) != pb) sesymself(neighsh);
13927  senext(neighsh, *searchsh);
13928  } else {
13929  // This side (startpt->pb) is outside. It is caused by rounding error.
13930  // Try the next side, i.e., (pc->startpt).
13931  senext2(*searchsh, neighsh);
13932  if (chkencflag) {
13933  // Do not cross boundary.
13934  if (isshsubseg(neighsh)) {
13935  *searchsh = neighsh;
13936  return ACROSSEDGE; // ACROSS_SEG
13937  }
13938  }
13939  spivotself(neighsh);
13940  if (sdest(neighsh) != pc) sesymself(neighsh);
13941  *searchsh = neighsh;
13942  }
13943  } else { // MOVE_CA
13944  senext2(*searchsh, neighsh);
13945  if (chkencflag) {
13946  // Do not cross boundary.
13947  if (isshsubseg(neighsh)) {
13948  *searchsh = neighsh;
13949  return ACROSSEDGE; // ACROSS_SEG
13950  }
13951  }
13952  spivotself(neighsh);
13953  if (neighsh.sh != NULL) {
13954  if (sdest(neighsh) != pc) sesymself(neighsh);
13955  *searchsh = neighsh;
13956  } else {
13957  // The same reason as above.
13958  // Try the next side, i.e., (startpt->pb).
13959  if (chkencflag) {
13960  // Do not cross boundary.
13961  if (isshsubseg(*searchsh)) {
13962  return ACROSSEDGE; // ACROSS_SEG
13963  }
13964  }
13965  spivot(*searchsh, neighsh);
13966  if (sorg(neighsh) != pb) sesymself(neighsh);
13967  senext(neighsh, *searchsh);
13968  }
13969  }
13970  } // while
13971 
13972  if (dir == SHAREEDGE) {
13973  if (insertsegflag) {
13974  // Insert the segment into the triangulation.
13975  face newseg;
13976  makeshellface(subsegs, &newseg);
13977  setshvertices(newseg, startpt, endpt, NULL);
13978  // Set the default segment marker.
13979  setshellmark(newseg, -1);
13980  ssbond(*searchsh, newseg);
13981  spivot(*searchsh, neighsh);
13982  if (neighsh.sh != NULL) {
13983  ssbond(neighsh, newseg);
13984  }
13985  }
13986  return dir;
13987  }
13988 
13989  if (dir == ACROSSVERT) {
13990  // A point is found collinear with this segment.
13991  if (reporterrorflag) {
13992  point pp = sdest(*searchsh);
13993  printf("PLC Error: A vertex lies in a segment in facet #%d.\n",
13994  shellmark(*searchsh));
13995  printf(" Vertex: [%d] (%g,%g,%g).\n",pointmark(pp),pp[0],pp[1],pp[2]);
13996  printf(" Segment: [%d, %d]\n", pointmark(startpt), pointmark(endpt));
13997  }
13998  return dir;
13999  }
14000 
14001  if (dir == ACROSSEDGE) {
14002  // Edge [b, c] intersects with the segment.
14003  senext(*searchsh, flipshs[0]);
14004  if (isshsubseg(flipshs[0])) {
14005  if (reporterrorflag) {
14006  REAL P[3], Q[3], tp = 0, tq = 0;
14007  linelineint(startpt, endpt, pb, pc, P, Q, &tp, &tq);
14008  printf("PLC Error: Two segments intersect at point (%g,%g,%g),",
14009  P[0], P[1], P[2]);
14010  printf(" in facet #%d.\n", shellmark(*searchsh));
14011  printf(" Segment 1: [%d, %d]\n", pointmark(pb), pointmark(pc));
14012  printf(" Segment 2: [%d, %d]\n", pointmark(startpt),pointmark(endpt));
14013  }
14014  return dir; // ACROSS_SEG
14015  }
14016  // Flip edge [b, c], queue unflipped edges (for Delaunay checks).
14017  spivot(flipshs[0], flipshs[1]);
14018  if (sorg(flipshs[1]) != sdest(flipshs[0])) sesymself(flipshs[1]);
14019  flip22(flipshs, 1, 0);
14020  // The flip may create an inverted triangle, check it.
14021  pa = sapex(flipshs[1]);
14022  pb = sapex(flipshs[0]);
14023  pc = sorg(flipshs[0]);
14024  pd = sdest(flipshs[0]);
14025  // Check if pa and pb are on the different sides of [pc, pd].
14026  // Re-use ori_ab, ori_ca for the tests.
14027  ori_ab = orient3d(pc, pd, dummypoint, pb);
14028  ori_ca = orient3d(pd, pc, dummypoint, pa);
14029  if (ori_ab <= 0) {
14030  flipshpush(&(flipshs[0]));
14031  } else if (ori_ca <= 0) {
14032  flipshpush(&(flipshs[1]));
14033  }
14034  // Set 'searchsh' s.t. its origin is 'startpt'.
14035  *searchsh = flipshs[0];
14036  }
14037 
14038  return sscoutsegment(searchsh, endpt, insertsegflag, reporterrorflag,
14039  chkencflag);
14040 }
14041 
14043 // //
14044 // scarveholes() Remove triangles not in the facet. //
14045 // //
14046 // This routine re-uses the two global arrays: caveshlist and caveshbdlist. //
14047 // //
14049 
14050 void tetgenmesh::scarveholes(int holes, REAL* holelist)
14051 {
14052  face *parysh, searchsh, neighsh;
14053  enum locateresult loc;
14054  int i, j;
14055 
14056  // Get all triangles. Infect unprotected convex hull triangles.
14057  smarktest(recentsh);
14058  caveshlist->newindex((void **) &parysh);
14059  *parysh = recentsh;
14060  for (i = 0; i < caveshlist->objects; i++) {
14061  parysh = (face *) fastlookup(caveshlist, i);
14062  searchsh = *parysh;
14063  searchsh.shver = 0;
14064  for (j = 0; j < 3; j++) {
14065  spivot(searchsh, neighsh);
14066  // Is this side on the convex hull?
14067  if (neighsh.sh != NULL) {
14068  if (!smarktested(neighsh)) {
14069  smarktest(neighsh);
14070  caveshlist->newindex((void **) &parysh);
14071  *parysh = neighsh;
14072  }
14073  } else {
14074  // A hull side. Check if it is protected by a segment.
14075  if (!isshsubseg(searchsh)) {
14076  // Not protected. Save this face.
14077  if (!sinfected(searchsh)) {
14078  sinfect(searchsh);
14079  caveshbdlist->newindex((void **) &parysh);
14080  *parysh = searchsh;
14081  }
14082  }
14083  }
14084  senextself(searchsh);
14085  }
14086  }
14087 
14088  // Infect the triangles in the holes.
14089  for (i = 0; i < 3 * holes; i += 3) {
14090  searchsh = recentsh;
14091  loc = slocate(&(holelist[i]), &searchsh, 1, 1, 0);
14092  if (loc != OUTSIDE) {
14093  sinfect(searchsh);
14094  caveshbdlist->newindex((void **) &parysh);
14095  *parysh = searchsh;
14096  }
14097  }
14098 
14099  // Find and infect all exterior triangles.
14100  for (i = 0; i < caveshbdlist->objects; i++) {
14101  parysh = (face *) fastlookup(caveshbdlist, i);
14102  searchsh = *parysh;
14103  searchsh.shver = 0;
14104  for (j = 0; j < 3; j++) {
14105  spivot(searchsh, neighsh);
14106  if (neighsh.sh != NULL) {
14107  if (!isshsubseg(searchsh)) {
14108  if (!sinfected(neighsh)) {
14109  sinfect(neighsh);
14110  caveshbdlist->newindex((void **) &parysh);
14111  *parysh = neighsh;
14112  }
14113  } else {
14114  sdissolve(neighsh); // Disconnect a protected face.
14115  }
14116  }
14117  senextself(searchsh);
14118  }
14119  }
14120 
14121  // Delete exterior triangles, unmark interior triangles.
14122  for (i = 0; i < caveshlist->objects; i++) {
14123  parysh = (face *) fastlookup(caveshlist, i);
14124  if (sinfected(*parysh)) {
14125  shellfacedealloc(subfaces, parysh->sh);
14126  } else {
14127  sunmarktest(*parysh);
14128  }
14129  }
14130 
14131  caveshlist->restart();
14132  caveshbdlist->restart();
14133 }
14134 
14136 // //
14137 // triangulate() Create a CDT for the facet. //
14138 // //
14139 // All vertices of the triangulation have type FACETVERTEX. The actual type //
14140 // of boundary vertices are set by the routine unifysements(). //
14141 // //
14142 // All segments created here will have a default marker '-1'. Some of these //
14143 // segments will get their actual marker defined in 'edgemarkerlist'. //
14144 // //
14146 
14147 int tetgenmesh::triangulate(int shmark, arraypool* ptlist, arraypool* conlist,
14148  int holes, REAL* holelist)
14149 {
14150  face searchsh, newsh, *parysh;
14151  face newseg, *paryseg;
14152  point pa, pb, pc, *ppt, *cons;
14153  int iloc;
14154  int i, j;
14155 
14156  if (b->verbose > 2) {
14157  printf(" f%d: %ld vertices, %ld segments", shmark, ptlist->objects,
14158  conlist->objects);
14159  if (holes > 0) {
14160  printf(", %d holes", holes);
14161  }
14162  printf(".\n");
14163  }
14164 
14165  if (ptlist->objects < 2l) {
14166  // Not a segment or a facet.
14167  return 1;
14168  } else if (ptlist->objects == 2l) {
14169  pa = * (point *) fastlookup(ptlist, 0);
14170  pb = * (point *) fastlookup(ptlist, 1);
14171  if (distance(pa, pb) > 0) {
14172  // It is a single segment.
14173  makeshellface(subsegs, &newseg);
14174  setshvertices(newseg, pa, pb, NULL);
14175  setshellmark(newseg, -1);
14176  }
14177  if (pointtype(pa) == VOLVERTEX) {
14178  setpointtype(pa, FACETVERTEX);
14179  }
14180  if (pointtype(pb) == VOLVERTEX) {
14181  setpointtype(pb, FACETVERTEX);
14182  }
14183  return 1;
14184  } else if (ptlist->objects == 3) {
14185  pa = * (point *) fastlookup(ptlist, 0);
14186  pb = * (point *) fastlookup(ptlist, 1);
14187  pc = * (point *) fastlookup(ptlist, 2);
14188  } else {
14189  // Calculate an above point of this facet.
14190  if (!calculateabovepoint(ptlist, &pa, &pb, &pc)) {
14191  if (!b->quiet) {
14192  printf("Warning: Unable to triangulate facet #%d. Skipped!\n",shmark);
14193  }
14194  return 0; // The point set is degenerate.
14195  }
14196  }
14197 
14198  // Create an initial triangulation.
14199  makeshellface(subfaces, &newsh);
14200  setshvertices(newsh, pa, pb, pc);
14201  setshellmark(newsh, shmark);
14202  recentsh = newsh;
14203 
14204  if (pointtype(pa) == VOLVERTEX) {
14205  setpointtype(pa, FACETVERTEX);
14206  }
14207  if (pointtype(pb) == VOLVERTEX) {
14208  setpointtype(pb, FACETVERTEX);
14209  }
14210  if (pointtype(pc) == VOLVERTEX) {
14211  setpointtype(pc, FACETVERTEX);
14212  }
14213 
14214  // Are there area constraints?
14215  if (b->quality && (in->facetconstraintlist != NULL)) {
14216  for (i = 0; i < in->numberoffacetconstraints; i++) {
14217  if (shmark == ((int) in->facetconstraintlist[i * 2])) {
14218  REAL area = in->facetconstraintlist[i * 2 + 1];
14219  setareabound(newsh, area);
14220  break;
14221  }
14222  }
14223  }
14224 
14225  if (ptlist->objects == 3) {
14226  // The triangulation only has one element.
14227  for (i = 0; i < 3; i++) {
14228  makeshellface(subsegs, &newseg);
14229  setshvertices(newseg, sorg(newsh), sdest(newsh), NULL);
14230  setshellmark(newseg, -1);
14231  ssbond(newsh, newseg);
14232  senextself(newsh);
14233  }
14234  return 1;
14235  }
14236 
14237  // Triangulate the facet. It may not success (due to rounding error, or
14238  // incorrect input data), use 'caveencshlist' and 'caveencseglist' are
14239  // re-used to store all the newly created subfaces and segments. So we
14240  // can clean them if the triangulation is not successful.
14241  caveencshlist->newindex((void **) &parysh);
14242  *parysh = newsh;
14243 
14244  // Incrementally build the triangulation.
14245  pinfect(pa);
14246  pinfect(pb);
14247  pinfect(pc);
14248  for (i = 0; i < ptlist->objects; i++) {
14249  ppt = (point *) fastlookup(ptlist, i);
14250  if (!pinfected(*ppt)) {
14251  searchsh = recentsh; // Start from 'recentsh'.
14252  iloc = (int) OUTSIDE;
14253  // Insert the vertex. Use Bowyer-Watson algo. Round the location.
14254  iloc = sinsertvertex(*ppt, &searchsh, NULL, iloc, 1, 1);
14255  if (iloc != ((int) ONVERTEX)) {
14256  // Point inserted successfully.
14257  if (pointtype(*ppt) == VOLVERTEX) {
14258  setpointtype(*ppt, FACETVERTEX);
14259  }
14260  // Save the set of new subfaces.
14261  for (j = 0; j < caveshbdlist->objects; j++) {
14262  // Get an old subface at edge [a, b].
14263  parysh = (face *) fastlookup(caveshbdlist, j);
14264  spivot(*parysh, searchsh); // The new subface [a, b, p].
14265  // Do not save a deleted new face (degenerated).
14266  if (searchsh.sh[3] != NULL) {
14267  caveencshlist->newindex((void **) &parysh);
14268  *parysh = searchsh;
14269  }
14270  }
14271  // Delete all removed subfaces.
14272  for (j = 0; j < caveshlist->objects; j++) {
14273  parysh = (face *) fastlookup(caveshlist, j);
14274  shellfacedealloc(subfaces, parysh->sh);
14275  }
14276  // Clear the global lists.
14277  caveshbdlist->restart();
14278  caveshlist->restart();
14279  cavesegshlist->restart();
14280  } else {
14281  // The facet triangulation is failed.
14282  break;
14283  }
14284  }
14285  } // i
14286  puninfect(pa);
14287  puninfect(pb);
14288  puninfect(pc);
14289 
14290  if (i < ptlist->objects) {
14291  //The facet triangulation is failed. Clean the new subfaces.
14292  // There is no new segment be created yet.
14293  if (!b->quiet) {
14294  printf("Warning: Fail to triangulate facet #%d. Skipped!\n", shmark);
14295  }
14296  for (i = 0; i < caveencshlist->objects; i++) {
14297  parysh = (face *) fastlookup(caveencshlist, i);
14298  if (parysh->sh[3] != NULL) {
14299  shellfacedealloc(subfaces, parysh->sh);
14300  }
14301  }
14302  caveencshlist->restart();
14303  return 0;
14304  }
14305 
14306  // Insert the segments.
14307  for (i = 0; i < conlist->objects; i++) {
14308  cons = (point *) fastlookup(conlist, i);
14309  searchsh = recentsh;
14310  iloc = (int) slocate(cons[0], &searchsh, 1, 1, 0);
14311  if (iloc != (int) ONVERTEX) {
14312  // Not found due to roundoff errors. Do a brute-force search.
14313  subfaces->traversalinit();
14314  searchsh.sh = shellfacetraverse(subfaces);
14315  while (searchsh.sh != NULL) {
14316  // Only search the subface in the same facet.
14317  if (shellmark(searchsh) == shmark) {
14318  if ((point) searchsh.sh[3] == cons[0]) {
14319  searchsh.shver = 0; break;
14320  } else if ((point) searchsh.sh[4] == cons[0]) {
14321  searchsh.shver = 2; break;
14322  } else if ((point) searchsh.sh[5] == cons[0]) {
14323  searchsh.shver = 4; break;
14324  }
14325  }
14326  searchsh.sh = shellfacetraverse(subfaces);
14327  }
14328  }
14329  // Recover the segment. Some edges may be flipped.
14330  if (sscoutsegment(&searchsh, cons[1], 1, 1, 0) != SHAREEDGE) {
14331  break; // Fail to recover a segment.
14332  }
14333  // Save this newseg.
14334  sspivot(searchsh, newseg);
14335  caveencseglist->newindex((void **) &paryseg);
14336  *paryseg = newseg;
14337  if (flipstack != NULL) {
14338  // Recover locally Delaunay edges.
14339  lawsonflip();
14340  }
14341  } // i
14342 
14343  if (i < conlist->objects) {
14344  if (!b->quiet) {
14345  printf("Warning: Fail to recover a segment in facet #%d. Skipped!\n",
14346  shmark);
14347  }
14348  for (i = 0; i < caveencshlist->objects; i++) {
14349  parysh = (face *) fastlookup(caveencshlist, i);
14350  if (parysh->sh[3] != NULL) {
14351  shellfacedealloc(subfaces, parysh->sh);
14352  }
14353  }
14354  for (i = 0; i < caveencseglist->objects; i++) {
14355  paryseg = (face *) fastlookup(caveencseglist, i);
14356  if (paryseg->sh[3] != NULL) {
14357  shellfacedealloc(subsegs, paryseg->sh);
14358  }
14359  }
14360  caveencshlist->restart();
14361  caveencseglist->restart();
14362  return 0;
14363  }
14364 
14365  // Remove exterior and hole triangles.
14366  scarveholes(holes, holelist);
14367 
14368  caveencshlist->restart();
14369  caveencseglist->restart();
14370  return 1;
14371 }
14372 
14374 // //
14375 // unifysegments() Remove redundant segments and create face links. //
14376 // //
14377 // After this routine, although segments are unique, but some of them may be //
14378 // removed later by mergefacet(). All vertices still have type FACETVERTEX. //
14379 // //
14381 
14382 void tetgenmesh::unifysegments()
14383 {
14384  badface *facelink = NULL, *newlinkitem, *f1, *f2;
14385  face *facperverlist, sface;
14386  face subsegloop, testseg;
14387  point torg, tdest;
14388  REAL ori1, ori2, ori3;
14389  REAL n1[3], n2[3];
14390  REAL cosang, ang, ang_tol;
14391  int *idx2faclist;
14392  int idx, k, m;
14393 
14394  if (b->verbose > 1) {
14395  printf(" Unifying segments.\n");
14396  }
14397  // The limit dihedral angle that two facets are not overlapping.
14398  ang_tol = b->facet_overlap_ang_tol / 180.0 * PI;
14399  if (ang_tol < 0.0) ang_tol = 0.0;
14400 
14401  // Create a mapping from vertices to subfaces.
14402  makepoint2submap(subfaces, idx2faclist, facperverlist);
14403 
14404 
14405  subsegloop.shver = 0;
14406  subsegs->traversalinit();
14407  subsegloop.sh = shellfacetraverse(subsegs);
14408  while (subsegloop.sh != (shellface *) NULL) {
14409  torg = sorg(subsegloop);
14410  tdest = sdest(subsegloop);
14411 
14412  idx = pointmark(torg) - in->firstnumber;
14413  // Loop through the set of subfaces containing 'torg'. Get all the
14414  // subfaces containing the edge (torg, tdest). Save and order them
14415  // in 'sfacelist', the ordering is defined by the right-hand rule
14416  // with thumb points from torg to tdest.
14417  for (k = idx2faclist[idx]; k < idx2faclist[idx + 1]; k++) {
14418  sface = facperverlist[k];
14419  // The face may be deleted if it is a duplicated face.
14420  if (sface.sh[3] == NULL) continue;
14421  // Search the edge torg->tdest.
14422  if (sdest(sface) != tdest) {
14423  senext2self(sface);
14424  sesymself(sface);
14425  }
14426  if (sdest(sface) != tdest) continue;
14427 
14428  // Save the face f in facelink.
14429  if (flippool->items >= 2) {
14430  f1 = facelink;
14431  for (m = 0; m < flippool->items - 1; m++) {
14432  f2 = f1->nextitem;
14433  ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(f2->ss));
14434  ori2 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface));
14435  if (ori1 > 0) {
14436  // apex(f2) is below f1.
14437  if (ori2 > 0) {
14438  // apex(f) is below f1 (see Fig.1).
14439  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
14440  if (ori3 > 0) {
14441  // apex(f) is below f2, insert it.
14442  break;
14443  } else if (ori3 < 0) {
14444  // apex(f) is above f2, continue.
14445  } else { // ori3 == 0;
14446  // f is coplanar and codirection with f2.
14447  report_overlapping_facets(&(f2->ss), &sface);
14448  break;
14449  }
14450  } else if (ori2 < 0) {
14451  // apex(f) is above f1 below f2, inset it (see Fig. 2).
14452  break;
14453  } else { // ori2 == 0;
14454  // apex(f) is coplanar with f1 (see Fig. 5).
14455  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
14456  if (ori3 > 0) {
14457  // apex(f) is below f2, insert it.
14458  break;
14459  } else {
14460  // f is coplanar and codirection with f1.
14461  report_overlapping_facets(&(f1->ss), &sface);
14462  break;
14463  }
14464  }
14465  } else if (ori1 < 0) {
14466  // apex(f2) is above f1.
14467  if (ori2 > 0) {
14468  // apex(f) is below f1, continue (see Fig. 3).
14469  } else if (ori2 < 0) {
14470  // apex(f) is above f1 (see Fig.4).
14471  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
14472  if (ori3 > 0) {
14473  // apex(f) is below f2, insert it.
14474  break;
14475  } else if (ori3 < 0) {
14476  // apex(f) is above f2, continue.
14477  } else { // ori3 == 0;
14478  // f is coplanar and codirection with f2.
14479  report_overlapping_facets(&(f2->ss), &sface);
14480  break;
14481  }
14482  } else { // ori2 == 0;
14483  // f is coplanar and with f1 (see Fig. 6).
14484  ori3 = orient3d(torg, tdest, sapex(f2->ss), sapex(sface));
14485  if (ori3 > 0) {
14486  // f is also codirection with f1.
14487  report_overlapping_facets(&(f1->ss), &sface);
14488  break;
14489  } else {
14490  // f is above f2, continue.
14491  }
14492  }
14493  } else { // ori1 == 0;
14494  // apex(f2) is coplanar with f1. By assumption, f1 is not
14495  // coplanar and codirection with f2.
14496  if (ori2 > 0) {
14497  // apex(f) is below f1, continue (see Fig. 7).
14498  } else if (ori2 < 0) {
14499  // apex(f) is above f1, insert it (see Fig. 7).
14500  break;
14501  } else { // ori2 == 0.
14502  // apex(f) is coplanar with f1 (see Fig. 8).
14503  // f is either codirection with f1 or is codirection with f2.
14504  facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL);
14505  facenormal(torg, tdest, sapex(sface), n2, 1, NULL);
14506  if (dot(n1, n2) > 0) {
14507  report_overlapping_facets(&(f1->ss), &sface);
14508  } else {
14509  report_overlapping_facets(&(f2->ss), &sface);
14510  }
14511  break;
14512  }
14513  }
14514  // Go to the next item;
14515  f1 = f2;
14516  } // for (m = 0; ...)
14517  if (sface.sh[3] != NULL) {
14518  // Insert sface between f1 and f2.
14519  newlinkitem = (badface *) flippool->alloc();
14520  newlinkitem->ss = sface;
14521  newlinkitem->nextitem = f1->nextitem;
14522  f1->nextitem = newlinkitem;
14523  }
14524  } else if (flippool->items == 1) {
14525  f1 = facelink;
14526  // Make sure that f is not coplanar and codirection with f1.
14527  ori1 = orient3d(torg, tdest, sapex(f1->ss), sapex(sface));
14528  if (ori1 == 0) {
14529  // f is coplanar with f1 (see Fig. 8).
14530  facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL);
14531  facenormal(torg, tdest, sapex(sface), n2, 1, NULL);
14532  if (dot(n1, n2) > 0) {
14533  // The two faces are codirectional as well.
14534  report_overlapping_facets(&(f1->ss), &sface);
14535  }
14536  }
14537  // Add this face to link if it is not deleted.
14538  if (sface.sh[3] != NULL) {
14539  // Add this face into link.
14540  newlinkitem = (badface *) flippool->alloc();
14541  newlinkitem->ss = sface;
14542  newlinkitem->nextitem = NULL;
14543  f1->nextitem = newlinkitem;
14544  }
14545  } else {
14546  // The first face.
14547  newlinkitem = (badface *) flippool->alloc();
14548  newlinkitem->ss = sface;
14549  newlinkitem->nextitem = NULL;
14550  facelink = newlinkitem;
14551  }
14552  } // for (k = idx2faclist[idx]; ...)
14553 
14554 
14555  // Set the connection between this segment and faces containing it,
14556  // at the same time, remove redundant segments.
14557  f1 = facelink;
14558  for (k = 0; k < flippool->items; k++) {
14559  sspivot(f1->ss, testseg);
14560  // If 'testseg' is not 'subsegloop' and is not dead, it is redundant.
14561  if ((testseg.sh != subsegloop.sh) && (testseg.sh[3] != NULL)) {
14562  shellfacedealloc(subsegs, testseg.sh);
14563  }
14564  // Bonds the subface and the segment together.
14565  ssbond(f1->ss, subsegloop);
14566  f1 = f1->nextitem;
14567  }
14568 
14569  // Create the face ring at the segment.
14570  if (flippool->items > 1) {
14571  f1 = facelink;
14572  for (k = 1; k <= flippool->items; k++) {
14573  k < flippool->items ? f2 = f1->nextitem : f2 = facelink;
14574  // Calculate the dihedral angle between the two facet.
14575  facenormal(torg, tdest, sapex(f1->ss), n1, 1, NULL);
14576  facenormal(torg, tdest, sapex(f2->ss), n2, 1, NULL);
14577  cosang = dot(n1, n2) / (sqrt(dot(n1, n1)) * sqrt(dot(n2, n2)));
14578  // Rounding.
14579  if (cosang > 1.0) cosang = 1.0;
14580  else if (cosang < -1.0) cosang = -1.0;
14581  ang = acos(cosang);
14582  if (ang < ang_tol) {
14583  // Two facets are treated as overlapping each other.
14584  report_overlapping_facets(&(f1->ss), &(f2->ss), ang);
14585  } else {
14586  // Record the smallest input dihedral angle.
14587  if (ang < minfacetdihed) {
14588  minfacetdihed = ang;
14589  }
14590  sbond1(f1->ss, f2->ss);
14591  }
14592  f1 = f2;
14593  }
14594  }
14595 
14596  flippool->restart();
14597 
14598  // Are there length constraints?
14599  if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
14600  int e1, e2;
14601  REAL len;
14602  for (k = 0; k < in->numberofsegmentconstraints; k++) {
14603  e1 = (int) in->segmentconstraintlist[k * 3];
14604  e2 = (int) in->segmentconstraintlist[k * 3 + 1];
14605  if (((pointmark(torg) == e1) && (pointmark(tdest) == e2)) ||
14606  ((pointmark(torg) == e2) && (pointmark(tdest) == e1))) {
14607  len = in->segmentconstraintlist[k * 3 + 2];
14608  setareabound(subsegloop, len);
14609  break;
14610  }
14611  }
14612  }
14613 
14614  subsegloop.sh = shellfacetraverse(subsegs);
14615  }
14616 
14617  delete [] idx2faclist;
14618  delete [] facperverlist;
14619 }
14620 
14622 // //
14623 // identifyinputedges() Identify input edges. //
14624 // //
14625 // A set of input edges is provided in the 'in->edgelist'. We find these //
14626 // edges in the surface mesh and make them segments of the mesh. //
14627 // //
14628 // It is possible that an input edge is not in any facet, i.e.,it is a float-//
14629 // segment inside the volume. //
14630 // //
14632 
14633 void tetgenmesh::identifyinputedges(point *idx2verlist)
14634 {
14635  face* shperverlist;
14636  int* idx2shlist;
14637  face searchsh, neighsh;
14638  face segloop, checkseg, newseg;
14639  point checkpt, pa = NULL, pb = NULL;
14640  int *endpts;
14641  int edgemarker;
14642  int idx, i, j;
14643 
14644  int e1, e2;
14645  REAL len;
14646 
14647  if (!b->quiet) {
14648  printf("Inserting edges ...\n");
14649  }
14650 
14651  // Construct a map from points to subfaces.
14652  makepoint2submap(subfaces, idx2shlist, shperverlist);
14653 
14654  // Process the set of input edges.
14655  for (i = 0; i < in->numberofedges; i++) {
14656  endpts = &(in->edgelist[(i << 1)]);
14657  if (endpts[0] == endpts[1]) {
14658  if (!b->quiet) {
14659  printf("Warning: Edge #%d is degenerated. Skipped.\n", i);
14660  }
14661  continue; // Skip a degenerated edge.
14662  }
14663  // Recall that all existing segments have a default marker '-1'.
14664  // We assign all identified segments a default marker '-2'.
14665  edgemarker = in->edgemarkerlist ? in->edgemarkerlist[i] : -2;
14666 
14667  // Find a face contains the edge.
14668  newseg.sh = NULL;
14669  searchsh.sh = NULL;
14670  idx = endpts[0] - in->firstnumber;
14671  for (j = idx2shlist[idx]; j < idx2shlist[idx + 1]; j++) {
14672  checkpt = sdest(shperverlist[j]);
14673  if (pointmark(checkpt) == endpts[1]) {
14674  searchsh = shperverlist[j];
14675  break; // Found.
14676  } else {
14677  checkpt = sapex(shperverlist[j]);
14678  if (pointmark(checkpt) == endpts[1]) {
14679  senext2(shperverlist[j], searchsh);
14680  sesymself(searchsh);
14681  break;
14682  }
14683  }
14684  } // j
14685 
14686  if (searchsh.sh != NULL) {
14687  // Check if this edge is already a segment of the mesh.
14688  sspivot(searchsh, checkseg);
14689  if (checkseg.sh != NULL) {
14690  // This segment already exist.
14691  newseg = checkseg;
14692  } else {
14693  // Create a new segment at this edge.
14694  pa = sorg(searchsh);
14695  pb = sdest(searchsh);
14696  makeshellface(subsegs, &newseg);
14697  setshvertices(newseg, pa, pb, NULL);
14698  ssbond(searchsh, newseg);
14699  spivot(searchsh, neighsh);
14700  if (neighsh.sh != NULL) {
14701  ssbond(neighsh, newseg);
14702  }
14703  }
14704  } else {
14705  // It is a dangling segment (not belong to any facets).
14706  // Get the two endpoints of this segment.
14707  pa = idx2verlist[endpts[0]];
14708  pb = idx2verlist[endpts[1]];
14709  if (pa == pb) {
14710  if (!b->quiet) {
14711  printf("Warning: Edge #%d is degenerated. Skipped.\n", i);
14712  }
14713  continue;
14714  }
14715  // Check if segment [a,b] already exists.
14716  // TODO: Change the brute-force search. Slow!
14717  point *ppt;
14718  subsegs->traversalinit();
14719  segloop.sh = shellfacetraverse(subsegs);
14720  while (segloop.sh != NULL) {
14721  ppt = (point *) &(segloop.sh[3]);
14722  if (((ppt[0] == pa) && (ppt[1] == pb)) ||
14723  ((ppt[0] == pb) && (ppt[1] == pa))) {
14724  // Found!
14725  newseg = segloop;
14726  break;
14727  }
14728  segloop.sh = shellfacetraverse(subsegs);
14729  }
14730  if (newseg.sh == NULL) {
14731  makeshellface(subsegs, &newseg);
14732  setshvertices(newseg, pa, pb, NULL);
14733  }
14734  }
14735 
14736  setshellmark(newseg, edgemarker);
14737 
14738  if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
14739  for (i = 0; i < in->numberofsegmentconstraints; i++) {
14740  e1 = (int) in->segmentconstraintlist[i * 3];
14741  e2 = (int) in->segmentconstraintlist[i * 3 + 1];
14742  if (((pointmark(pa) == e1) && (pointmark(pb) == e2)) ||
14743  ((pointmark(pa) == e2) && (pointmark(pb) == e1))) {
14744  len = in->segmentconstraintlist[i * 3 + 2];
14745  setareabound(newseg, len);
14746  break;
14747  }
14748  }
14749  }
14750  } // i
14751 
14752  delete [] shperverlist;
14753  delete [] idx2shlist;
14754 }
14755 
14757 // //
14758 // mergefacets() Merge adjacent facets. //
14759 // //
14761 
14762 void tetgenmesh::mergefacets()
14763 {
14764  face parentsh, neighsh, neineish;
14765  face segloop;
14766  point pa, pb, pc, pd;
14767  REAL n1[3], n2[3];
14768  REAL cosang, cosang_tol;
14769 
14770 
14771  // Allocate an array to save calcaulated dihedral angles at segments.
14772  arraypool *dihedangarray = new arraypool(sizeof(double), 10);
14773  REAL *paryang = NULL;
14774 
14775  // First, remove coplanar segments.
14776  // The dihedral angle bound for two different facets.
14777  cosang_tol = cos(b->facet_separate_ang_tol / 180.0 * PI);
14778 
14779  subsegs->traversalinit();
14780  segloop.sh = shellfacetraverse(subsegs);
14781  while (segloop.sh != (shellface *) NULL) {
14782  // Only remove a segment if it has a marker '-1'.
14783  if (shellmark(segloop) != -1) {
14784  segloop.sh = shellfacetraverse(subsegs);
14785  continue;
14786  }
14787  spivot(segloop, parentsh);
14788  if (parentsh.sh != NULL) {
14789  spivot(parentsh, neighsh);
14790  if (neighsh.sh != NULL) {
14791  spivot(neighsh, neineish);
14792  if (neineish.sh == parentsh.sh) {
14793  // Exactly two subfaces at this segment.
14794  // Only merge them if they have the same boundary marker.
14795  if (shellmark(parentsh) == shellmark(neighsh)) {
14796  pa = sorg(segloop);
14797  pb = sdest(segloop);
14798  pc = sapex(parentsh);
14799  pd = sapex(neighsh);
14800  // Calculate the dihedral angle at the segment [a,b].
14801  facenormal(pa, pb, pc, n1, 1, NULL);
14802  facenormal(pa, pb, pd, n2, 1, NULL);
14803  cosang = dot(n1, n2) / (sqrt(dot(n1, n1)) * sqrt(dot(n2, n2)));
14804  if (cosang < cosang_tol) {
14805  ssdissolve(parentsh);
14806  ssdissolve(neighsh);
14807  shellfacedealloc(subsegs, segloop.sh);
14808  // Add the edge to flip stack.
14809  flipshpush(&parentsh);
14810  } else {
14811  // Save 'cosang' to avoid re-calculate it.
14812  // Re-use the pointer at the first segment.
14813  dihedangarray->newindex((void **) &paryang);
14814  *paryang = cosang;
14815  segloop.sh[6] = (shellface) paryang;
14816  }
14817  }
14818  } // if (neineish.sh == parentsh.sh)
14819  }
14820  }
14821  segloop.sh = shellfacetraverse(subsegs);
14822  }
14823 
14824  // Second, remove ridge segments at small angles.
14825  // The dihedral angle bound for two different facets.
14826  cosang_tol = cos(b->facet_small_ang_tol / 180.0 * PI);
14827  REAL cosang_sep_tol = cos((b->facet_separate_ang_tol - 5.0) / 180.0 * PI);
14828  face shloop;
14829  face seg1, seg2;
14830  REAL cosang1, cosang2;
14831  int i, j;
14832 
14833  subfaces->traversalinit();
14834  shloop.sh = shellfacetraverse(subfaces);
14835  while (shloop.sh != (shellface *) NULL) {
14836  for (i = 0; i < 3; i++) {
14837  if (isshsubseg(shloop)) {
14838  senext(shloop, neighsh);
14839  if (isshsubseg(neighsh)) {
14840  // Found two segments sharing at one vertex.
14841  // Check if they form a small angle.
14842  pa = sorg(shloop);
14843  pb = sdest(shloop);
14844  pc = sapex(shloop);
14845  for (j = 0; j < 3; j++) n1[j] = pa[j] - pb[j];
14846  for (j = 0; j < 3; j++) n2[j] = pc[j] - pb[j];
14847  cosang = dot(n1, n2) / (sqrt(dot(n1, n1)) * sqrt(dot(n2, n2)));
14848  if (cosang > cosang_tol) {
14849  // Found a small angle.
14850  segloop.sh = NULL;
14851  sspivot(shloop, seg1);
14852  sspivot(neighsh, seg2);
14853  if (seg1.sh[6] != NULL) {
14854  paryang = (REAL *) (seg1.sh[6]);
14855  cosang1 = *paryang;
14856  } else {
14857  cosang1 = 1.0; // 0 degree;
14858  }
14859  if (seg2.sh[6] != NULL) {
14860  paryang = (REAL *) (seg2.sh[6]);
14861  cosang2 = *paryang;
14862  } else {
14863  cosang2 = 1.0; // 0 degree;
14864  }
14865  if (cosang1 < cosang_sep_tol) {
14866  if (cosang2 < cosang_sep_tol) {
14867  if (cosang1 < cosang2) {
14868  segloop = seg1;
14869  } else {
14870  segloop = seg2;
14871  }
14872  } else {
14873  segloop = seg1;
14874  }
14875  } else {
14876  if (cosang2 < cosang_sep_tol) {
14877  segloop = seg2;
14878  }
14879  }
14880  if (segloop.sh != NULL) {
14881  // Remove this segment.
14882  segloop.shver = 0;
14883  spivot(segloop, parentsh);
14884  spivot(parentsh, neighsh);
14885  ssdissolve(parentsh);
14886  ssdissolve(neighsh);
14887  shellfacedealloc(subsegs, segloop.sh);
14888  // Add the edge to flip stack.
14889  flipshpush(&parentsh);
14890  break;
14891  }
14892  }
14893  } // if (isshsubseg)
14894  } // if (isshsubseg)
14895  senextself(shloop);
14896  }
14897  shloop.sh = shellfacetraverse(subfaces);
14898  }
14899 
14900  delete dihedangarray;
14901 
14902  if (flipstack != NULL) {
14903  lawsonflip(); // Recover Delaunayness.
14904  }
14905 }
14906 
14908 // //
14909 // meshsurface() Create a surface mesh of the input PLC. //
14910 // //
14912 
14913 void tetgenmesh::meshsurface()
14914 {
14915  arraypool *ptlist, *conlist;
14916  point *idx2verlist;
14917  point tstart, tend, *pnewpt, *cons;
14918  tetgenio::facet *f;
14919  tetgenio::polygon *p;
14920  int end1, end2;
14921  int shmark, i, j;
14922 
14923  if (!b->quiet) {
14924  printf("Creating surface mesh ...\n");
14925  }
14926 
14927  // Create a map from indices to points.
14928  makeindex2pointmap(idx2verlist);
14929 
14930  // Initialize arrays (block size: 2^8 = 256).
14931  ptlist = new arraypool(sizeof(point *), 8);
14932  conlist = new arraypool(2 * sizeof(point *), 8);
14933 
14934  // Loop the facet list, triangulate each facet.
14935  for (shmark = 1; shmark <= in->numberoffacets; shmark++) {
14936 
14937  // Get a facet F.
14938  f = &in->facetlist[shmark - 1];
14939 
14940  // Process the duplicated points first, they are marked with type
14941  // DUPLICATEDVERTEX. If p and q are duplicated, and p'index > q's,
14942  // then p is substituted by q.
14943  if (dupverts > 0l) {
14944  // Loop all polygons of this facet.
14945  for (i = 0; i < f->numberofpolygons; i++) {
14946  p = &(f->polygonlist[i]);
14947  // Loop other vertices of this polygon.
14948  for (j = 0; j < p->numberofvertices; j++) {
14949  end1 = p->vertexlist[j];
14950  tstart = idx2verlist[end1];
14951  if (pointtype(tstart) == DUPLICATEDVERTEX) {
14952  // Reset the index of vertex-j.
14953  tend = point2ppt(tstart);
14954  end2 = pointmark(tend);
14955  p->vertexlist[j] = end2;
14956  }
14957  }
14958  }
14959  }
14960 
14961  // Loop polygons of F, get the set of vertices and segments.
14962  for (i = 0; i < f->numberofpolygons; i++) {
14963  // Get a polygon.
14964  p = &(f->polygonlist[i]);
14965  // Get the first vertex.
14966  end1 = p->vertexlist[0];
14967  if ((end1 < in->firstnumber) ||
14968  (end1 >= in->firstnumber + in->numberofpoints)) {
14969  if (!b->quiet) {
14970  printf("Warning: Invalid the 1st vertex %d of polygon", end1);
14971  printf(" %d in facet %d.\n", i + 1, shmark);
14972  }
14973  continue; // Skip this polygon.
14974  }
14975  tstart = idx2verlist[end1];
14976  // Add tstart to V if it haven't been added yet.
14977  if (!pinfected(tstart)) {
14978  pinfect(tstart);
14979  ptlist->newindex((void **) &pnewpt);
14980  *pnewpt = tstart;
14981  }
14982  // Loop other vertices of this polygon.
14983  for (j = 1; j <= p->numberofvertices; j++) {
14984  // get a vertex.
14985  if (j < p->numberofvertices) {
14986  end2 = p->vertexlist[j];
14987  } else {
14988  end2 = p->vertexlist[0]; // Form a loop from last to first.
14989  }
14990  if ((end2 < in->firstnumber) ||
14991  (end2 >= in->firstnumber + in->numberofpoints)) {
14992  if (!b->quiet) {
14993  printf("Warning: Invalid vertex %d in polygon %d", end2, i + 1);
14994  printf(" in facet %d.\n", shmark);
14995  }
14996  } else {
14997  if (end1 != end2) {
14998  // 'end1' and 'end2' form a segment.
14999  tend = idx2verlist[end2];
15000  // Add tstart to V if it haven't been added yet.
15001  if (!pinfected(tend)) {
15002  pinfect(tend);
15003  ptlist->newindex((void **) &pnewpt);
15004  *pnewpt = tend;
15005  }
15006  // Save the segment in S (conlist).
15007  conlist->newindex((void **) &cons);
15008  cons[0] = tstart;
15009  cons[1] = tend;
15010  // Set the start for next continuous segment.
15011  end1 = end2;
15012  tstart = tend;
15013  } else {
15014  // Two identical vertices mean an isolated vertex of F.
15015  if (p->numberofvertices > 2) {
15016  // This may be an error in the input, anyway, we can continue
15017  // by simply skipping this segment.
15018  if (!b->quiet) {
15019  printf("Warning: Polygon %d has two identical verts", i + 1);
15020  printf(" in facet %d.\n", shmark);
15021  }
15022  }
15023  // Ignore this vertex.
15024  }
15025  }
15026  // Is the polygon degenerate (a segment or a vertex)?
15027  if (p->numberofvertices == 2) break;
15028  }
15029  }
15030  // Unmark vertices.
15031  for (i = 0; i < ptlist->objects; i++) {
15032  pnewpt = (point *) fastlookup(ptlist, i);
15033  puninfect(*pnewpt);
15034  }
15035 
15036  // Triangulate F into a CDT.
15037  // If in->facetmarklist is NULL, use the default marker -1.
15038  triangulate(in->facetmarkerlist ? in->facetmarkerlist[shmark - 1] : -1,
15039  ptlist, conlist, f->numberofholes, f->holelist);
15040 
15041  // Clear working lists.
15042  ptlist->restart();
15043  conlist->restart();
15044  }
15045 
15046  if (!b->diagnose) {
15047  // Remove redundant segments and build the face links.
15048  unifysegments();
15049  if (in->numberofedges > 0) {
15050  // There are input segments. Insert them.
15051  identifyinputedges(idx2verlist);
15052  }
15053  if (!b->psc && !b->nomergefacet &&
15054  (!b->nobisect || (b->nobisect && !b->nobisect_nomerge))) {
15055  // Merge coplanar facets.
15056  mergefacets();
15057  }
15058  }
15059 
15060  if (b->object == tetgenbehavior::STL) {
15061  // Remove redundant vertices (for .stl input mesh).
15062  jettisonnodes();
15063  }
15064 
15065  if (b->verbose) {
15066  printf(" %ld (%ld) subfaces (segments).\n", subfaces->items,
15067  subsegs->items);
15068  }
15069 
15070  // The total number of iunput segments.
15071  insegments = subsegs->items;
15072 
15073  delete [] idx2verlist;
15074  delete ptlist;
15075  delete conlist;
15076 }
15077 
15079 // //
15080 // interecursive() Recursively do intersection test on a set of triangles.//
15081 // //
15082 // Recursively split the set 'subfacearray' of subfaces into two sets using //
15083 // a cut plane parallel to x-, or, y-, or z-axis. The split criteria are //
15084 // follows. Assume the cut plane is H, and H+ denotes the left halfspace of //
15085 // H, and H- denotes the right halfspace of H; and s be a subface: //
15086 // //
15087 // (1) If all points of s lie at H+, put it into left array; //
15088 // (2) If all points of s lie at H-, put it into right array; //
15089 // (3) If some points of s lie at H+ and some of lie at H-, or some //
15090 // points lie on H, put it into both arraies. //
15091 // //
15092 // Partitions by x-axis if axis == '0'; by y-axis if axis == '1'; by z-axis //
15093 // if axis == '2'. If current cut plane is parallel to the x-axis, the next //
15094 // one will be parallel to y-axis, and the next one after the next is z-axis,//
15095 // and then alternately return back to x-axis. //
15096 // //
15097 // Stop splitting when the number of triangles of the input array is not //
15098 // decreased anymore. Do tests on the current set. //
15099 // //
15101 
15102 void tetgenmesh::interecursive(shellface** subfacearray, int arraysize,
15103  int axis, REAL bxmin, REAL bxmax, REAL bymin,
15104  REAL bymax, REAL bzmin, REAL bzmax,
15105  int* internum)
15106 {
15107  shellface **leftarray, **rightarray;
15108  face sface1, sface2;
15109  point p1, p2, p3;
15110  point p4, p5, p6;
15111  enum interresult intersect;
15112  REAL split;
15113  bool toleft, toright;
15114  int leftsize, rightsize;
15115  int i, j;
15116 
15117  if (b->verbose > 2) {
15118  printf(" Recur %d faces. Bbox (%g, %g, %g),(%g, %g, %g). %s-axis\n",
15119  arraysize, bxmin, bymin, bzmin, bxmax, bymax, bzmax,
15120  axis == 0 ? "x" : (axis == 1 ? "y" : "z"));
15121  }
15122 
15123  leftarray = new shellface*[arraysize];
15124  if (leftarray == NULL) {
15125  terminatetetgen(this, 1);
15126  }
15127  rightarray = new shellface*[arraysize];
15128  if (rightarray == NULL) {
15129  terminatetetgen(this, 1);
15130  }
15131  leftsize = rightsize = 0;
15132 
15133  if (axis == 0) {
15134  // Split along x-axis.
15135  split = 0.5 * (bxmin + bxmax);
15136  } else if (axis == 1) {
15137  // Split along y-axis.
15138  split = 0.5 * (bymin + bymax);
15139  } else {
15140  // Split along z-axis.
15141  split = 0.5 * (bzmin + bzmax);
15142  }
15143 
15144  for (i = 0; i < arraysize; i++) {
15145  sface1.sh = subfacearray[i];
15146  p1 = (point) sface1.sh[3];
15147  p2 = (point) sface1.sh[4];
15148  p3 = (point) sface1.sh[5];
15149  toleft = toright = false;
15150  if (p1[axis] < split) {
15151  toleft = true;
15152  if (p2[axis] >= split || p3[axis] >= split) {
15153  toright = true;
15154  }
15155  } else if (p1[axis] > split) {
15156  toright = true;
15157  if (p2[axis] <= split || p3[axis] <= split) {
15158  toleft = true;
15159  }
15160  } else {
15161  // p1[axis] == split;
15162  toleft = true;
15163  toright = true;
15164  }
15165  if (toleft) {
15166  leftarray[leftsize] = sface1.sh;
15167  leftsize++;
15168  }
15169  if (toright) {
15170  rightarray[rightsize] = sface1.sh;
15171  rightsize++;
15172  }
15173  }
15174 
15175  if (leftsize < arraysize && rightsize < arraysize) {
15176  // Continue to partition the input set. Now 'subfacearray' has been
15177  // split into two sets, it's memory can be freed. 'leftarray' and
15178  // 'rightarray' will be freed in the next recursive (after they're
15179  // partitioned again or performing tests).
15180  delete [] subfacearray;
15181  // Continue to split these two sets.
15182  if (axis == 0) {
15183  interecursive(leftarray, leftsize, 1, bxmin, split, bymin, bymax,
15184  bzmin, bzmax, internum);
15185  interecursive(rightarray, rightsize, 1, split, bxmax, bymin, bymax,
15186  bzmin, bzmax, internum);
15187  } else if (axis == 1) {
15188  interecursive(leftarray, leftsize, 2, bxmin, bxmax, bymin, split,
15189  bzmin, bzmax, internum);
15190  interecursive(rightarray, rightsize, 2, bxmin, bxmax, split, bymax,
15191  bzmin, bzmax, internum);
15192  } else {
15193  interecursive(leftarray, leftsize, 0, bxmin, bxmax, bymin, bymax,
15194  bzmin, split, internum);
15195  interecursive(rightarray, rightsize, 0, bxmin, bxmax, bymin, bymax,
15196  split, bzmax, internum);
15197  }
15198  } else {
15199  if (b->verbose > 1) {
15200  printf(" Checking intersecting faces.\n");
15201  }
15202  // Perform a brute-force compare on the set.
15203  for (i = 0; i < arraysize; i++) {
15204  sface1.sh = subfacearray[i];
15205  p1 = (point) sface1.sh[3];
15206  p2 = (point) sface1.sh[4];
15207  p3 = (point) sface1.sh[5];
15208  for (j = i + 1; j < arraysize; j++) {
15209  sface2.sh = subfacearray[j];
15210  p4 = (point) sface2.sh[3];
15211  p5 = (point) sface2.sh[4];
15212  p6 = (point) sface2.sh[5];
15213  intersect = (enum interresult) tri_tri_inter(p1, p2, p3, p4, p5, p6);
15214  if (intersect == INTERSECT || intersect == SHAREFACE) {
15215  if (!b->quiet) {
15216  if (intersect == INTERSECT) {
15217  printf(" Facet #%d intersects facet #%d at triangles:\n",
15218  shellmark(sface1), shellmark(sface2));
15219  printf(" (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
15220  pointmark(p1), pointmark(p2), pointmark(p3),
15221  pointmark(p4), pointmark(p5), pointmark(p6));
15222  } else {
15223  printf(" Facet #%d duplicates facet #%d at triangle:\n",
15224  shellmark(sface1), shellmark(sface2));
15225  printf(" (%4d, %4d, %4d) and (%4d, %4d, %4d)\n",
15226  pointmark(p1), pointmark(p2), pointmark(p3),
15227  pointmark(p4), pointmark(p5), pointmark(p6));
15228  }
15229  }
15230  // Increase the number of intersecting pairs.
15231  (*internum)++;
15232  // Infect these two faces (although they may already be infected).
15233  sinfect(sface1);
15234  sinfect(sface2);
15235  }
15236  }
15237  }
15238  // Don't forget to free all three arrays. No further partition.
15239  delete [] leftarray;
15240  delete [] rightarray;
15241  delete [] subfacearray;
15242  }
15243 }
15244 
15246 // //
15247 // detectinterfaces() Detect intersecting triangles. //
15248 // //
15249 // Given a set of triangles, find the pairs of intersecting triangles from //
15250 // them. Here the set of triangles is in 'subfaces' which is a surface mesh //
15251 // of a PLC (.poly or .smesh). //
15252 // //
15253 // To detect whether two triangles are intersecting is done by the routine //
15254 // 'tri_tri_inter()'. The algorithm for the test is very simple and stable. //
15255 // It is based on geometric orientation test which uses exact arithmetics. //
15256 // //
15257 // Use divide-and-conquer algorithm for reducing the number of intersection //
15258 // tests. Start from the bounding box of the input point set, recursively //
15259 // partition the box into smaller boxes, until the number of triangles in a //
15260 // box is not decreased anymore. Then perform triangle-triangle tests on the //
15261 // remaining set of triangles. The memory allocated in the input set is //
15262 // freed immediately after it has been partitioned into two arrays. So it //
15263 // can be re-used for the consequent partitions. //
15264 // //
15265 // On return, the pool 'subfaces' will be cleared, and only the intersecting //
15266 // triangles remain for output (to a .face file). //
15267 // //
15269 
15270 void tetgenmesh::detectinterfaces()
15271 {
15272  shellface **subfacearray;
15273  face shloop;
15274  int internum;
15275  int i;
15276 
15277  if (!b->quiet) {
15278  printf("Detecting self-intersecting facets...\n");
15279  }
15280 
15281  // Construct a map from indices to subfaces;
15282  subfacearray = new shellface*[subfaces->items];
15283  subfaces->traversalinit();
15284  shloop.sh = shellfacetraverse(subfaces);
15285  i = 0;
15286  while (shloop.sh != (shellface *) NULL) {
15287  subfacearray[i] = shloop.sh;
15288  shloop.sh = shellfacetraverse(subfaces);
15289  i++;
15290  }
15291 
15292  internum = 0;
15293  // Recursively split the set of triangles into two sets using a cut plane
15294  // parallel to x-, or, y-, or z-axis. Stop splitting when the number
15295  // of subfaces is not decreasing anymore. Do tests on the current set.
15296  interecursive(subfacearray, subfaces->items, 0, xmin, xmax, ymin, ymax,
15297  zmin, zmax, &internum);
15298 
15299  if (!b->quiet) {
15300  if (internum > 0) {
15301  printf("\n!! Found %d pairs of faces are intersecting.\n\n", internum);
15302  } else {
15303  printf("\nNo faces are intersecting.\n\n");
15304  }
15305  }
15306 
15307  if (internum > 0) {
15308  // Traverse all subfaces, deallocate those have not been infected (they
15309  // are not intersecting faces). Uninfect those have been infected.
15310  // After this loop, only intersecting faces remain.
15311  subfaces->traversalinit();
15312  shloop.sh = shellfacetraverse(subfaces);
15313  while (shloop.sh != (shellface *) NULL) {
15314  if (sinfected(shloop)) {
15315  suninfect(shloop);
15316  } else {
15317  shellfacedealloc(subfaces, shloop.sh);
15318  }
15319  shloop.sh = shellfacetraverse(subfaces);
15320  }
15321  } else {
15322  // Deallocate all subfaces.
15323  subfaces->restart();
15324  }
15325 }
15326 
15330 
15334 
15336 // //
15337 // makesegmentendpointsmap() Create a map from a segment to its endpoints.//
15338 // //
15339 // The map is saved in the array 'segmentendpointslist'. The length of this //
15340 // array is twice the number of segments. Each segment is assigned a unique //
15341 // index (starting from 0). //
15342 // //
15344 
15345 void tetgenmesh::makesegmentendpointsmap()
15346 {
15347  arraypool *segptlist;
15348  face segloop, prevseg, nextseg;
15349  point eorg, edest, *parypt;
15350  int segindex = 0, idx = 0;
15351  int i;
15352 
15353  if (b->verbose > 0) {
15354  printf(" Creating the segment-endpoints map.\n");
15355  }
15356 
15357  segptlist = new arraypool(2 * sizeof(point), 10);
15358 
15359  // A segment s may have been split into many subsegments. Operate the one
15360  // which contains the origin of s. Then mark the rest of subsegments.
15361  subsegs->traversalinit();
15362  segloop.sh = shellfacetraverse(subsegs);
15363  segloop.shver = 0;
15364  while (segloop.sh != NULL) {
15365  senext2(segloop, prevseg);
15366  spivotself(prevseg);
15367  if (prevseg.sh == NULL) {
15368  eorg = sorg(segloop);
15369  edest = sdest(segloop);
15370  setfacetindex(segloop, segindex);
15371  senext(segloop, nextseg);
15372  spivotself(nextseg);
15373  while (nextseg.sh != NULL) {
15374  setfacetindex(nextseg, segindex);
15375  nextseg.shver = 0;
15376  if (sorg(nextseg) != edest) sesymself(nextseg);
15377  edest = sdest(nextseg);
15378  // Go the next connected subsegment at edest.
15379  senextself(nextseg);
15380  spivotself(nextseg);
15381  }
15382  segptlist->newindex((void **) &parypt);
15383  parypt[0] = eorg;
15384  parypt[1] = edest;
15385  segindex++;
15386  }
15387  segloop.sh = shellfacetraverse(subsegs);
15388  }
15389 
15390  if (b->verbose) {
15391  printf(" Found %ld segments.\n", segptlist->objects);
15392  }
15393 
15394  segmentendpointslist = new point[segptlist->objects * 2];
15395 
15396  totalworkmemory += (segptlist->objects * 2) * sizeof(point *);
15397 
15398  for (i = 0; i < segptlist->objects; i++) {
15399  parypt = (point *) fastlookup(segptlist, i);
15400  segmentendpointslist[idx++] = parypt[0];
15401  segmentendpointslist[idx++] = parypt[1];
15402  }
15403 
15404  delete segptlist;
15405 }
15406 
15408 // //
15409 // finddirection() Find the tet on the path from one point to another. //
15410 // //
15411 // The path starts from 'searchtet''s origin and ends at 'endpt'. On finish, //
15412 // 'searchtet' contains a tet on the path, its origin does not change. //
15413 // //
15414 // The return value indicates one of the following cases (let 'searchtet' be //
15415 // abcd, a is the origin of the path): //
15416 // - ACROSSVERT, edge ab is collinear with the path; //
15417 // - ACROSSEDGE, edge bc intersects with the path; //
15418 // - ACROSSFACE, face bcd intersects with the path. //
15419 // //
15420 // WARNING: This routine is designed for convex triangulations, and will not //
15421 // generally work after the holes and concavities have been carved. //
15422 // //
15424 
15425 enum tetgenmesh::interresult
15426  tetgenmesh::finddirection(triface* searchtet, point endpt)
15427 {
15428  triface neightet;
15429  point pa, pb, pc, pd;
15430  enum {HMOVE, RMOVE, LMOVE} nextmove;
15431  REAL hori, rori, lori;
15432  int t1ver;
15433  int s;
15434 
15435  // The origin is fixed.
15436  pa = org(*searchtet);
15437  if ((point) searchtet->tet[7] == dummypoint) {
15438  // A hull tet. Choose the neighbor of its base face.
15439  decode(searchtet->tet[3], *searchtet);
15440  // Reset the origin to be pa.
15441  if ((point) searchtet->tet[4] == pa) {
15442  searchtet->ver = 11;
15443  } else if ((point) searchtet->tet[5] == pa) {
15444  searchtet->ver = 3;
15445  } else if ((point) searchtet->tet[6] == pa) {
15446  searchtet->ver = 7;
15447  } else {
15448  searchtet->ver = 0;
15449  }
15450  }
15451 
15452  pb = dest(*searchtet);
15453  // Check whether the destination or apex is 'endpt'.
15454  if (pb == endpt) {
15455  // pa->pb is the search edge.
15456  return ACROSSVERT;
15457  }
15458 
15459  pc = apex(*searchtet);
15460  if (pc == endpt) {
15461  // pa->pc is the search edge.
15462  eprevesymself(*searchtet);
15463  return ACROSSVERT;
15464  }
15465 
15466  // Walk through tets around pa until the right one is found.
15467  while (1) {
15468 
15469  pd = oppo(*searchtet);
15470  // Check whether the opposite vertex is 'endpt'.
15471  if (pd == endpt) {
15472  // pa->pd is the search edge.
15473  esymself(*searchtet);
15474  enextself(*searchtet);
15475  return ACROSSVERT;
15476  }
15477  // Check if we have entered outside of the domain.
15478  if (pd == dummypoint) {
15479  // This is possible when the mesh is non-convex.
15480  if (nonconvex) {
15481  return ACROSSFACE; // return ACROSSSUB; // Hit a bounday.
15482  } else {
15483  terminatetetgen(this, 2);
15484  }
15485  }
15486 
15487  // Now assume that the base face abc coincides with the horizon plane,
15488  // and d lies above the horizon. The search point 'endpt' may lie
15489  // above or below the horizon. We test the orientations of 'endpt'
15490  // with respect to three planes: abc (horizon), bad (right plane),
15491  // and acd (left plane).
15492  hori = orient3d(pa, pb, pc, endpt);
15493  rori = orient3d(pb, pa, pd, endpt);
15494  lori = orient3d(pa, pc, pd, endpt);
15495 
15496  // Now decide the tet to move. It is possible there are more than one
15497  // tets are viable moves. Is so, randomly choose one.
15498  if (hori > 0) {
15499  if (rori > 0) {
15500  if (lori > 0) {
15501  // Any of the three neighbors is a viable move.
15502  s = randomnation(3);
15503  if (s == 0) {
15504  nextmove = HMOVE;
15505  } else if (s == 1) {
15506  nextmove = RMOVE;
15507  } else {
15508  nextmove = LMOVE;
15509  }
15510  } else {
15511  // Two tets, below horizon and below right, are viable.
15512  if (randomnation(2)) {
15513  nextmove = HMOVE;
15514  } else {
15515  nextmove = RMOVE;
15516  }
15517  }
15518  } else {
15519  if (lori > 0) {
15520  // Two tets, below horizon and below left, are viable.
15521  if (randomnation(2)) {
15522  nextmove = HMOVE;
15523  } else {
15524  nextmove = LMOVE;
15525  }
15526  } else {
15527  // The tet below horizon is chosen.
15528  nextmove = HMOVE;
15529  }
15530  }
15531  } else {
15532  if (rori > 0) {
15533  if (lori > 0) {
15534  // Two tets, below right and below left, are viable.
15535  if (randomnation(2)) {
15536  nextmove = RMOVE;
15537  } else {
15538  nextmove = LMOVE;
15539  }
15540  } else {
15541  // The tet below right is chosen.
15542  nextmove = RMOVE;
15543  }
15544  } else {
15545  if (lori > 0) {
15546  // The tet below left is chosen.
15547  nextmove = LMOVE;
15548  } else {
15549  // 'endpt' lies either on the plane(s) or across face bcd.
15550  if (hori == 0) {
15551  if (rori == 0) {
15552  // pa->'endpt' is COLLINEAR with pa->pb.
15553  return ACROSSVERT;
15554  }
15555  if (lori == 0) {
15556  // pa->'endpt' is COLLINEAR with pa->pc.
15557  eprevesymself(*searchtet); // [a,c,d]
15558  return ACROSSVERT;
15559  }
15560  // pa->'endpt' crosses the edge pb->pc.
15561  return ACROSSEDGE;
15562  }
15563  if (rori == 0) {
15564  if (lori == 0) {
15565  // pa->'endpt' is COLLINEAR with pa->pd.
15566  esymself(*searchtet); // face bad.
15567  enextself(*searchtet); // face [a,d,b]
15568  return ACROSSVERT;
15569  }
15570  // pa->'endpt' crosses the edge pb->pd.
15571  esymself(*searchtet); // face bad.
15572  enextself(*searchtet); // face adb
15573  return ACROSSEDGE;
15574  }
15575  if (lori == 0) {
15576  // pa->'endpt' crosses the edge pc->pd.
15577  eprevesymself(*searchtet); // [a,c,d]
15578  return ACROSSEDGE;
15579  }
15580  // pa->'endpt' crosses the face bcd.
15581  return ACROSSFACE;
15582  }
15583  }
15584  }
15585 
15586  // Move to the next tet, fix pa as its origin.
15587  if (nextmove == RMOVE) {
15588  fnextself(*searchtet);
15589  } else if (nextmove == LMOVE) {
15590  eprevself(*searchtet);
15591  fnextself(*searchtet);
15592  enextself(*searchtet);
15593  } else { // HMOVE
15594  fsymself(*searchtet);
15595  enextself(*searchtet);
15596  }
15597  pb = dest(*searchtet);
15598  pc = apex(*searchtet);
15599 
15600  } // while (1)
15601 
15602 }
15603 
15605 // //
15606 // scoutsegment() Search an edge in the tetrahedralization. //
15607 // //
15608 // If the edge is found, it returns SHAREEDGE, and 'searchtet' returns the //
15609 // edge from startpt to endpt. //
15610 // //
15611 // If the edge is missing, it returns either ACROSSEDGE or ACROSSFACE, which //
15612 // indicates that the edge intersects an edge or a face. If 'refpt' is NULL,//
15613 // 'searchtet' returns the edge or face. If 'refpt' is not NULL, it returns //
15614 // a vertex which encroaches upon this edge, and 'searchtet' returns a tet //
15615 // which containing 'refpt'. //
15616 // //
15617 // The parameter 'sedge' is used to report self-intersection. It is the //
15618 // whose endpoints are 'startpt' and 'endpt'. It must not be a NULL.
15619 // //
15621 
15622 #pragma GCC diagnostic push
15623 #pragma GCC diagnostic ignored "-Wunused-parameter"
15624 enum tetgenmesh::interresult tetgenmesh::scoutsegment(point startpt,point endpt,
15625  face *sedge, triface* searchtet, point* refpt, arraypool* intfacelist)
15626 {
15627  point pd;
15628  enum interresult dir;
15629  int t1ver;
15630 
15631  if (b->verbose > 2) {
15632  printf(" Scout seg (%d, %d).\n",pointmark(startpt),pointmark(endpt));
15633  }
15634 
15635  point2tetorg(startpt, *searchtet);
15636  dir = finddirection(searchtet, endpt);
15637 
15638  if (dir == ACROSSVERT) {
15639  pd = dest(*searchtet);
15640  if (pd == endpt) {
15641  if (issubseg(*searchtet)) {
15642  report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
15643  }
15644  return SHAREEDGE;
15645  } else {
15646  // A point is on the path.
15647  report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
15648  return ACROSSVERT;
15649  }
15650  }
15651 
15652  // dir is either ACROSSEDGE or ACROSSFACE.
15653  enextesymself(*searchtet); // Go to the opposite face.
15654  fsymself(*searchtet); // Enter the adjacent tet.
15655 
15656  if (dir == ACROSSEDGE) {
15657  // Check whether two segments are intersecting.
15658  if (issubseg(*searchtet)) {
15659  report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
15660  }
15661  } else if (dir == ACROSSFACE) {
15662  if (checksubfaceflag) {
15663  // Check whether a segment and a subface are intersecting.
15664  if (issubface(*searchtet)) {
15665  report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
15666  }
15667  }
15668  } else {
15669  terminatetetgen(this, 2);
15670  }
15671 
15672  if (refpt == NULL) {
15673  // Do not need a reference point. Return.
15674  return dir;
15675  }
15676 
15677  triface neightet, reftet;
15678  point pa, pb, pc;
15679  REAL angmax, ang;
15680  int types[2], poss[4];
15681  int pos = 0, i, j;
15682 
15683  pa = org(*searchtet);
15684  angmax = interiorangle(pa, startpt, endpt, NULL);
15685  *refpt = pa;
15686  pb = dest(*searchtet);
15687  ang = interiorangle(pb, startpt, endpt, NULL);
15688  if (ang > angmax) {
15689  angmax = ang;
15690  *refpt = pb;
15691  }
15692  pc = apex(*searchtet);
15693  ang = interiorangle(pc, startpt, endpt, NULL);
15694  if (ang > angmax) {
15695  angmax = ang;
15696  *refpt = pc;
15697  }
15698  reftet = *searchtet; // Save the tet containing the refpt.
15699 
15700  // Search intersecting faces along the segment.
15701  while (1) {
15702 
15703 
15704  pd = oppo(*searchtet);
15705 
15706 
15707  // Stop if we meet 'endpt'.
15708  if (pd == endpt) break;
15709 
15710  ang = interiorangle(pd, startpt, endpt, NULL);
15711  if (ang > angmax) {
15712  angmax = ang;
15713  *refpt = pd;
15714  reftet = *searchtet;
15715  }
15716 
15717  // Find a face intersecting the segment.
15718  if (dir == ACROSSFACE) {
15719  // One of the three oppo faces in 'searchtet' intersects the segment.
15720  neightet = *searchtet;
15721  j = (neightet.ver & 3); // j is the current face number.
15722  for (i = j + 1; i < j + 4; i++) {
15723  neightet.ver = (i % 4);
15724  pa = org(neightet);
15725  pb = dest(neightet);
15726  pc = apex(neightet);
15727  pd = oppo(neightet); // The above point.
15728  if (tri_edge_test(pa, pb, pc, startpt, endpt, pd, 1, types, poss)) {
15729  dir = (enum interresult) types[0];
15730  pos = poss[0];
15731  break;
15732  } else {
15733  dir = DISJOINT;
15734  pos = 0;
15735  }
15736  }
15737  } else if (dir == ACROSSEDGE) {
15738  // Check the two opposite faces (of the edge) in 'searchtet'.
15739  for (i = 0; i < 2; i++) {
15740  if (i == 0) {
15741  enextesym(*searchtet, neightet);
15742  } else {
15743  eprevesym(*searchtet, neightet);
15744  }
15745  pa = org(neightet);
15746  pb = dest(neightet);
15747  pc = apex(neightet);
15748  pd = oppo(neightet); // The above point.
15749  if (tri_edge_test(pa, pb, pc, startpt, endpt, pd, 1, types, poss)) {
15750  dir = (enum interresult) types[0];
15751  pos = poss[0];
15752  break;
15753  } else {
15754  dir = DISJOINT;
15755  pos = 0;
15756  }
15757  }
15758  if (dir == DISJOINT) {
15759  // No intersection. Rotate to the next tet at the edge.
15760  dir = ACROSSEDGE;
15761  fnextself(*searchtet);
15762  continue;
15763  }
15764  }
15765 
15766  if (dir == ACROSSVERT) {
15767  // This segment passing a vertex. Choose it and return.
15768  for (i = 0; i < pos; i++) {
15769  enextself(neightet);
15770  }
15771  eprev(neightet, *searchtet);
15772  // dest(*searchtet) lies on the segment.
15773  report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
15774  return ACROSSVERT;
15775  } else if (dir == ACROSSEDGE) {
15776  // Get the edge intersects with the segment.
15777  for (i = 0; i < pos; i++) {
15778  enextself(neightet);
15779  }
15780  }
15781  // Go to the next tet.
15782  fsym(neightet, *searchtet);
15783 
15784  if (dir == ACROSSEDGE) {
15785  // Check whether two segments are intersecting.
15786  if (issubseg(*searchtet)) {
15787  report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
15788  }
15789  } else if (dir == ACROSSFACE) {
15790  if (checksubfaceflag) {
15791  // Check whether a segment and a subface are intersecting.
15792  if (issubface(*searchtet)) {
15793  report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
15794  }
15795  }
15796  } else {
15797  terminatetetgen(this, 2);
15798  }
15799 
15800  } // while (1)
15801 
15802  // A valid reference point should inside the diametrial circumsphere of
15803  // the missing segment, i.e., it encroaches upon it.
15804  if (2.0 * angmax < PI) {
15805  *refpt = NULL;
15806  }
15807 
15808 
15809  *searchtet = reftet;
15810  return dir;
15811 }
15812 #pragma GCC diagnostic pop
15813 
15815 // //
15816 // getsteinerpointonsegment() Get a Steiner point on a segment. //
15817 // //
15818 // Return '1' if 'refpt' lies on an adjacent segment of this segment. Other- //
15819 // wise, return '0'. //
15820 // //
15822 
15823 int tetgenmesh::getsteinerptonsegment(face* seg, point refpt, point steinpt)
15824 {
15825  point ei = sorg(*seg);
15826  point ej = sdest(*seg);
15827  int adjflag = 0, i;
15828 
15829  if (refpt != NULL) {
15830  REAL L, L1, t;
15831 
15832  if (pointtype(refpt) == FREESEGVERTEX) {
15833  face parentseg;
15834  sdecode(point2sh(refpt), parentseg);
15835  int sidx1 = getfacetindex(parentseg);
15836  point far_pi = segmentendpointslist[sidx1 * 2];
15837  point far_pj = segmentendpointslist[sidx1 * 2 + 1];
15838  int sidx2 = getfacetindex(*seg);
15839  point far_ei = segmentendpointslist[sidx2 * 2];
15840  point far_ej = segmentendpointslist[sidx2 * 2 + 1];
15841  if ((far_pi == far_ei) || (far_pj == far_ei)) {
15842  // Create a Steiner point at the intersection of the segment
15843  // [far_ei, far_ej] and the sphere centered at far_ei with
15844  // radius |far_ei - refpt|.
15845  L = distance(far_ei, far_ej);
15846  L1 = distance(far_ei, refpt);
15847  t = L1 / L;
15848  for (i = 0; i < 3; i++) {
15849  steinpt[i] = far_ei[i] + t * (far_ej[i] - far_ei[i]);
15850  }
15851  adjflag = 1;
15852  } else if ((far_pi == far_ej) || (far_pj == far_ej)) {
15853  L = distance(far_ei, far_ej);
15854  L1 = distance(far_ej, refpt);
15855  t = L1 / L;
15856  for (i = 0; i < 3; i++) {
15857  steinpt[i] = far_ej[i] + t * (far_ei[i] - far_ej[i]);
15858  }
15859  adjflag = 1;
15860  } else {
15861  // Cut the segment by the projection point of refpt.
15862  projpt2edge(refpt, ei, ej, steinpt);
15863  }
15864  } else {
15865  // Cut the segment by the projection point of refpt.
15866  projpt2edge(refpt, ei, ej, steinpt);
15867  }
15868 
15869  // Make sure that steinpt is not too close to ei and ej.
15870  L = distance(ei, ej);
15871  L1 = distance(steinpt, ei);
15872  t = L1 / L;
15873  if ((t < 0.2) || (t > 0.8)) {
15874  // Split the point at the middle.
15875  for (i = 0; i < 3; i++) {
15876  steinpt[i] = ei[i] + 0.5 * (ej[i] - ei[i]);
15877  }
15878  }
15879  } else {
15880  // Split the point at the middle.
15881  for (i = 0; i < 3; i++) {
15882  steinpt[i] = ei[i] + 0.5 * (ej[i] - ei[i]);
15883  }
15884  }
15885 
15886 
15887  return adjflag;
15888 }
15889 
15890 
15891 
15893 // //
15894 // delaunizesegments() Recover segments in a DT. //
15895 // //
15896 // All segments need to be recovered are in 'subsegstack' (Q). They will be //
15897 // be recovered one by one (in a random order). //
15898 // //
15899 // Given a segment s in the Q, this routine first queries s in the DT, if s //
15900 // matches an edge in DT, it is 'locked' at the edge. Otherwise, s is split //
15901 // by inserting a new point p in both the DT and itself. The two new subseg- //
15902 // ments of s are queued in Q. The process continues until Q is empty. //
15903 // //
15905 
15906 void tetgenmesh::delaunizesegments()
15907 {
15908  triface searchtet, spintet;
15909  face searchsh;
15910  face sseg, *psseg;
15911  point refpt, newpt;
15912  enum interresult dir;
15913  insertvertexflags ivf;
15914  int t1ver;
15915 
15916 
15917  ivf.bowywat = 1; // Use Bowyer-Watson insertion.
15918  ivf.sloc = (int) ONEDGE; // on 'sseg'.
15919  ivf.sbowywat = 1; // Use Bowyer-Watson insertion.
15920  ivf.assignmeshsize = b->metric;
15921  ivf.smlenflag = useinsertradius; // Return the closet mesh vertex.
15922 
15923  // Loop until 'subsegstack' is empty.
15924  while (subsegstack->objects > 0l) {
15925  // seglist is used as a stack.
15926  subsegstack->objects--;
15927  psseg = (face *) fastlookup(subsegstack, subsegstack->objects);
15928  sseg = *psseg;
15929 
15930  // Check if this segment has been recovered.
15931  sstpivot1(sseg, searchtet);
15932  if (searchtet.tet != NULL) {
15933  continue; // Not a missing segment.
15934  }
15935 
15936  // Search the segment.
15937  dir = scoutsegment(sorg(sseg), sdest(sseg), &sseg,&searchtet,&refpt,NULL);
15938 
15939  if (dir == SHAREEDGE) {
15940  // Found this segment, insert it.
15941  // Let the segment remember an adjacent tet.
15942  sstbond1(sseg, searchtet);
15943  // Bond the segment to all tets containing it.
15944  spintet = searchtet;
15945  do {
15946  tssbond1(spintet, sseg);
15947  fnextself(spintet);
15948  } while (spintet.tet != searchtet.tet);
15949  } else {
15950  if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
15951  // The segment is missing. Split it.
15952  // Create a new point.
15953  makepoint(&newpt, FREESEGVERTEX);
15954  //setpointtype(newpt, FREESEGVERTEX);
15955  getsteinerptonsegment(&sseg, refpt, newpt);
15956 
15957  // Start searching from 'searchtet'.
15958  ivf.iloc = (int) OUTSIDE;
15959  // Insert the new point into the tetrahedralization T.
15960  // Missing segments and subfaces are queued for recovery.
15961  // Note that T is convex (nonconvex = 0).
15962  if (insertpoint(newpt, &searchtet, &searchsh, &sseg, &ivf)) {
15963  // The new point has been inserted.
15964  st_segref_count++;
15965  if (steinerleft > 0) steinerleft--;
15966  if (useinsertradius) {
15967  save_segmentpoint_insradius(newpt, ivf.parentpt, ivf.smlen);
15968  }
15969  } else {
15970  if (ivf.iloc == (int) NEARVERTEX) {
15971  // The new point (in the segment) is very close to an existing
15972  // vertex -- a small feature is detected.
15973  point nearpt = org(searchtet);
15974  if (pointtype(nearpt) == FREESEGVERTEX) {
15975  face parentseg;
15976  sdecode(point2sh(nearpt), parentseg);
15977  point p1 = farsorg(sseg);
15978  point p2 = farsdest(sseg);
15979  point p3 = farsorg(parentseg);
15980  point p4 = farsdest(parentseg);
15981  printf("Two segments are very close to each other.\n");
15982  printf(" Segment 1: [%d, %d] #%d\n", pointmark(p1),
15983  pointmark(p2), shellmark(sseg));
15984  printf(" Segment 2: [%d, %d] #%d\n", pointmark(p3),
15985  pointmark(p4), shellmark(parentseg));
15986  terminatetetgen(this, 4);
15987  } else {
15988  terminatetetgen(this, 2);
15989  }
15990  } else if (ivf.iloc == (int) ONVERTEX) {
15991  // The new point (in the segment) is coincident with an existing
15992  // vertex -- a self-intersection is detected.
15993  eprevself(searchtet);
15994  report_selfint_edge(sorg(sseg), sdest(sseg), &sseg, &searchtet,
15995  ACROSSVERT);
15996  } else {
15997  // An unknown case. Report a bug.
15998  terminatetetgen(this, 2);
15999  }
16000  }
16001  } else {
16002  // An unknown case. Report a bug.
16003  terminatetetgen(this, 2);
16004  }
16005  }
16006  } // while
16007 }
16008 
16010 // //
16011 // scoutsubface() Search subface in the tetrahedralization. //
16012 // //
16013 // 'searchsh' is searched in T. If it exists, it is 'locked' at the face in //
16014 // T. 'searchtet' refers to the face. Otherwise, it is missing. //
16015 // //
16016 // The parameter 'shflag' indicates whether 'searchsh' is a boundary face or //
16017 // not. It is possible that 'searchsh' is a temporarily subface that is used //
16018 // as a cavity boundary face. //
16019 // //
16021 
16022 int tetgenmesh::scoutsubface(face* searchsh, triface* searchtet, int shflag)
16023 {
16024  point pa = sorg(*searchsh);
16025  point pb = sdest(*searchsh);
16026 
16027  // Get a tet whose origin is a.
16028  point2tetorg(pa, *searchtet);
16029  // Search the edge [a,b].
16030  enum interresult dir = finddirection(searchtet, pb);
16031  if (dir == ACROSSVERT) {
16032  // Check validity of a PLC.
16033  if (dest(*searchtet) != pb) {
16034  if (shflag) {
16035  // A vertex lies on the search edge.
16036  report_selfint_edge(pa, pb, searchsh, searchtet, dir);
16037  } else {
16038  terminatetetgen(this, 2);
16039  }
16040  }
16041  int t1ver;
16042  // The edge exists. Check if the face exists.
16043  point pc = sapex(*searchsh);
16044  // Searchtet holds edge [a,b]. Search a face with apex c.
16045  triface spintet = *searchtet;
16046  while (1) {
16047  if (apex(spintet) == pc) {
16048  // Found a face matching to 'searchsh'!
16049  if (!issubface(spintet)) {
16050  // Insert 'searchsh'.
16051  tsbond(spintet, *searchsh);
16052  fsymself(spintet);
16053  sesymself(*searchsh);
16054  tsbond(spintet, *searchsh);
16055  *searchtet = spintet;
16056  return 1;
16057  } else {
16058  terminatetetgen(this, 2);
16059  }
16060  }
16061  fnextself(spintet);
16062  if (spintet.tet == searchtet->tet) break;
16063  }
16064  }
16065 
16066  return 0;
16067 }
16068 
16070 // //
16071 // formregion() Form the missing region of a missing subface. //
16072 // //
16073 // 'missh' is a missing subface. From it we form a missing region R which is //
16074 // a connected region formed by a set of missing subfaces of a facet. //
16075 // Comment: There should be no segment inside R. //
16076 // //
16077 // 'missingshs' returns the list of subfaces in R. All subfaces in this list //
16078 // are oriented as the 'missh'. 'missingshbds' returns the list of boundary //
16079 // edges (tetrahedral handles) of R. 'missingshverts' returns all vertices //
16080 // of R. They are all pmarktested. //
16081 // //
16082 // Except the first one (which is 'missh') in 'missingshs', each subface in //
16083 // this list represents an internal edge of R, i.e., it is missing in the //
16084 // tetrahedralization. Since R may contain interior vertices, not all miss- //
16085 // ing edges can be found by this way. //
16087 
16088 void tetgenmesh::formregion(face* missh, arraypool* missingshs,
16089  arraypool* missingshbds, arraypool* missingshverts)
16090 {
16091  triface searchtet, spintet;
16092  face neighsh, *parysh;
16093  face neighseg, fakeseg;
16094  point pa, pb, *parypt;
16095  enum interresult dir;
16096  int t1ver;
16097  int i, j;
16098 
16099  smarktest(*missh);
16100  missingshs->newindex((void **) &parysh);
16101  *parysh = *missh;
16102 
16103  // Incrementally find other missing subfaces.
16104  for (i = 0; i < missingshs->objects; i++) {
16105  missh = (face *) fastlookup(missingshs, i);
16106  for (j = 0; j < 3; j++) {
16107  pa = sorg(*missh);
16108  pb = sdest(*missh);
16109  point2tetorg(pa, searchtet);
16110  dir = finddirection(&searchtet, pb);
16111  if (dir != ACROSSVERT) {
16112  // This edge is missing. Its neighbor is a missing subface.
16113  spivot(*missh, neighsh);
16114  if (!smarktested(neighsh)) {
16115  // Adjust the face orientation.
16116  if (sorg(neighsh) != pb) sesymself(neighsh);
16117  smarktest(neighsh);
16118  missingshs->newindex((void **) &parysh);
16119  *parysh = neighsh;
16120  }
16121  } else {
16122  if (dest(searchtet) != pb) {
16123  // Report a PLC problem.
16124  report_selfint_edge(pa, pb, missh, &searchtet, dir);
16125  }
16126  }
16127  // Collect the vertices of R.
16128  if (!pmarktested(pa)) {
16129  pmarktest(pa);
16130  missingshverts->newindex((void **) &parypt);
16131  *parypt = pa;
16132  }
16133  senextself(*missh);
16134  } // j
16135  } // i
16136 
16137  // Get the boundary edges of R.
16138  for (i = 0; i < missingshs->objects; i++) {
16139  missh = (face *) fastlookup(missingshs, i);
16140  for (j = 0; j < 3; j++) {
16141  spivot(*missh, neighsh);
16142  if ((neighsh.sh == NULL) || !smarktested(neighsh)) {
16143  // A boundary edge of R.
16144  // Let the segment point to the adjacent tet.
16145  point2tetorg(sorg(*missh), searchtet);
16146  finddirection(&searchtet, sdest(*missh));
16147  missingshbds->newindex((void **) &parysh);
16148  *parysh = *missh;
16149  // Check if this edge is a segment.
16150  sspivot(*missh, neighseg);
16151  if (neighseg.sh == NULL) {
16152  // Temporarily create a segment at this edge.
16153  makeshellface(subsegs, &fakeseg);
16154  setsorg(fakeseg, sorg(*missh));
16155  setsdest(fakeseg, sdest(*missh));
16156  sinfect(fakeseg); // Mark it as faked.
16157  // Connect it to all tets at this edge.
16158  spintet = searchtet;
16159  while (1) {
16160  tssbond1(spintet, fakeseg);
16161  fnextself(spintet);
16162  if (spintet.tet == searchtet.tet) break;
16163  }
16164  neighseg = fakeseg;
16165  }
16166  // Let the segment and the boundary edge point to each other.
16167  ssbond(*missh, neighseg);
16168  sstbond1(neighseg, searchtet);
16169  }
16170  senextself(*missh);
16171  } // j
16172  } // i
16173 
16174 
16175  // Unmarktest collected missing subfaces.
16176  for (i = 0; i < missingshs->objects; i++) {
16177  parysh = (face *) fastlookup(missingshs, i);
16178  sunmarktest(*parysh);
16179  }
16180 }
16181 
16183 // //
16184 // scoutcrossedge() Search an edge that crosses the missing region. //
16185 // //
16186 // Return 1 if a crossing edge is found. It is returned by 'crosstet'. More- //
16187 // over, the edge is oriented such that its origin lies below R. Return 0 //
16188 // if no such edge is found. //
16189 // //
16190 // Assumption: All vertices of the missing region are marktested. //
16191 // //
16193 
16194 int tetgenmesh::scoutcrossedge(triface& crosstet, arraypool* missingshbds,
16195  arraypool* missingshs)
16196 {
16197  triface searchtet, spintet, neightet;
16198  face oldsh, searchsh, *parysh;
16199  face neighseg;
16200  point pa, pb, pc, pd, pe;
16201  REAL ori;
16202  int types[2], poss[4];
16203  int searchflag, interflag;
16204  int t1ver;
16205  int i, j;
16206 
16207  searchflag = 0;
16208 
16209  // Search the first new subface to fill the region.
16210  for (i = 0; i < missingshbds->objects && !searchflag; i++) {
16211  parysh = (face *) fastlookup(missingshbds, i);
16212  sspivot(*parysh, neighseg);
16213  sstpivot1(neighseg, searchtet);
16214  if (org(searchtet) != sorg(*parysh)) {
16215  esymself(searchtet);
16216  }
16217  spintet = searchtet;
16218  while (1) {
16219  if (pmarktested(apex(spintet))) {
16220  // A possible interior face.
16221  neightet = spintet;
16222  oldsh = *parysh;
16223  // Try to recover an interior edge.
16224  for (j = 0; j < 2; j++) {
16225  enextself(neightet);
16226  if (!issubseg(neightet)) {
16227  if (j == 0) {
16228  senext(oldsh, searchsh);
16229  } else {
16230  senext2(oldsh, searchsh);
16231  sesymself(searchsh);
16232  esymself(neightet);
16233  }
16234  // Calculate a lifted point.
16235  pa = sorg(searchsh);
16236  pb = sdest(searchsh);
16237  pc = sapex(searchsh);
16238  pd = dest(neightet);
16239  calculateabovepoint4(pa, pb, pc, pd);
16240  // The lifted point must lie above 'searchsh'.
16241  ori = orient3d(pa, pb, pc, dummypoint);
16242  if (ori > 0) {
16243  sesymself(searchsh);
16244  senextself(searchsh);
16245  } else if (ori == 0) {
16246  terminatetetgen(this, 2);
16247  }
16248  if (sscoutsegment(&searchsh,dest(neightet),0,0,1)==SHAREEDGE) {
16249  // Insert a temp segment to protect the recovered edge.
16250  face tmpseg;
16251  makeshellface(subsegs, &tmpseg);
16252  ssbond(searchsh, tmpseg);
16253  spivotself(searchsh);
16254  ssbond(searchsh, tmpseg);
16255  // Recover locally Delaunay edges.
16256  lawsonflip();
16257  // Delete the tmp segment.
16258  spivot(tmpseg, searchsh);
16259  ssdissolve(searchsh);
16260  spivotself(searchsh);
16261  ssdissolve(searchsh);
16262  shellfacedealloc(subsegs, tmpseg.sh);
16263  searchflag = 1;
16264  } else {
16265  // Undo the performed flips.
16266  if (flipstack != NULL) {
16267  lawsonflip();
16268  }
16269  }
16270  break;
16271  } // if (!issubseg(neightet))
16272  } // j
16273  if (searchflag) break;
16274  } // if (pmarktested(apex(spintet)))
16275  fnextself(spintet);
16276  if (spintet.tet == searchtet.tet) break;
16277  }
16278  } // i
16279 
16280  if (searchflag) {
16281  // Remove faked segments.
16282  face checkseg;
16283  // Remark: We should not use the array 'missingshbds', since the flips may
16284  // change the subfaces. We search them from the subfaces in R.
16285  for (i = 0; i < missingshs->objects; i++) {
16286  parysh = (face *) fastlookup(missingshs, i);
16287  oldsh = *parysh;
16288  for (j = 0; j < 3; j++) {
16289  if (isshsubseg(oldsh)) {
16290  sspivot(oldsh, checkseg);
16291  if (sinfected(checkseg)) {
16292  // It's a faked segment. Delete it.
16293  sstpivot1(checkseg, searchtet);
16294  spintet = searchtet;
16295  while (1) {
16296  tssdissolve1(spintet);
16297  fnextself(spintet);
16298  if (spintet.tet == searchtet.tet) break;
16299  }
16300  shellfacedealloc(subsegs, checkseg.sh);
16301  ssdissolve(oldsh);
16302  }
16303  }
16304  senextself(oldsh);
16305  } // j
16306  }
16307 
16308  fillregioncount++;
16309 
16310  return 0;
16311  } // if (i < missingshbds->objects)
16312 
16313  searchflag = -1;
16314 
16315  for (j = 0; j < missingshbds->objects && (searchflag == -1); j++) {
16316  parysh = (face *) fastlookup(missingshbds, j);
16317  sspivot(*parysh, neighseg);
16318  sstpivot1(neighseg, searchtet);
16319  interflag = 0;
16320  // Let 'spintet' be [#,#,d,e] where [#,#] is the boundary edge of R.
16321  spintet = searchtet;
16322  while (1) {
16323  pd = apex(spintet);
16324  pe = oppo(spintet);
16325  // Skip a hull edge.
16326  if ((pd != dummypoint) && (pe != dummypoint)) {
16327  // Skip an edge containing a vertex of R.
16328  if (!pmarktested(pd) && !pmarktested(pe)) {
16329  // Check if [d,e] intersects R.
16330  for (i = 0; i < missingshs->objects && !interflag; i++) {
16331  parysh = (face *) fastlookup(missingshs, i);
16332  pa = sorg(*parysh);
16333  pb = sdest(*parysh);
16334  pc = sapex(*parysh);
16335  interflag=tri_edge_test(pa, pb, pc, pd, pe, NULL, 1, types, poss);
16336  if (interflag > 0) {
16337  if (interflag == 2) {
16338  // They intersect at a single point.
16339  if ((types[0] == (int) ACROSSFACE) ||
16340  (types[0] == (int) ACROSSEDGE)) {
16341  // Go to the crossing edge [d,e,#,#].
16342  edestoppo(spintet, crosstet); // // [d,e,#,#].
16343  if (issubseg(crosstet)) {
16344  // It is a segment. Report a PLC problem.
16345  report_selfint_face(pa, pb, pc, parysh, &crosstet,
16346  interflag, types, poss);
16347  } else {
16348  triface chkface = crosstet;
16349  while (1) {
16350  if (issubface(chkface)) break;
16351  fsymself(chkface);
16352  if (chkface.tet == crosstet.tet) break;
16353  }
16354  if (issubface(chkface)) {
16355  // Two subfaces are intersecting.
16356  report_selfint_face(pa, pb, pc, parysh, &chkface,
16357  interflag, types, poss);
16358  }
16359  }
16360  // Adjust the edge such that d lies below [a,b,c].
16361  ori = orient3d(pa, pb, pc, pd);
16362  if (ori < 0) {
16363  esymself(crosstet);
16364  }
16365  searchflag = 1;
16366  } else {
16367  // An improper intersection type, ACROSSVERT, TOUCHFACE,
16368  // TOUCHEDGE, SHAREVERT, ...
16369  // Maybe it is due to a PLC problem.
16370  report_selfint_face(pa, pb, pc, parysh, &crosstet,
16371  interflag, types, poss);
16372  }
16373  }
16374  break;
16375  } // if (interflag > 0)
16376  }
16377  }
16378  }
16379  // Leave search at this bdry edge if an intersection is found.
16380  if (interflag > 0) break;
16381  // Go to the next tetrahedron.
16382  fnextself(spintet);
16383  if (spintet.tet == searchtet.tet) break;
16384  } // while (1)
16385  } // j
16386 
16387  return searchflag;
16388 }
16389 
16391 // //
16392 // formcavity() Form the cavity of a missing region. //
16393 // //
16394 // The missing region R is formed by a set of missing subfaces 'missingshs'. //
16395 // In the following, we assume R is horizontal and oriented. (All subfaces //
16396 // of R are oriented in the same way.) 'searchtet' is a tetrahedron [d,e,#, //
16397 // #] which intersects R in its interior, where the edge [d,e] intersects R, //
16398 // and d lies below R. //
16399 // //
16400 // 'crosstets' returns the set of crossing tets. Every tet in it has the //
16401 // form [d,e,#,#] where [d,e] is a crossing edge, and d lies below R. The //
16402 // set of tets form the cavity C, which is divided into two parts by R, one //
16403 // at top and one at bottom. 'topfaces' and 'botfaces' return the upper and //
16404 // lower boundary faces of C. 'toppoints' contains vertices of 'crosstets' //
16405 // in the top part of C, and so does 'botpoints'. Both 'toppoints' and //
16406 // 'botpoints' contain vertices of R. //
16407 // //
16408 // Important: This routine assumes all vertices of the facet containing this //
16409 // subface are marked, i.e., pmarktested(p) returns true. //
16410 // //
16412 
16413 bool tetgenmesh::formcavity(triface* searchtet, arraypool* missingshs,
16414  arraypool* crosstets, arraypool* topfaces,
16415  arraypool* botfaces, arraypool* toppoints,
16416  arraypool* botpoints)
16417 {
16418  arraypool *crossedges;
16419  triface spintet, neightet, chkface, *parytet;
16420  face *parysh = NULL;
16421  point pa, pd, pe, *parypt;
16422  bool testflag, invalidflag;
16423  int intflag, types[2], poss[4];
16424  int t1ver;
16425  int i, j, k;
16426 
16427  // Temporarily re-use 'topfaces' for all crossing edges.
16428  crossedges = topfaces;
16429 
16430  if (b->verbose > 2) {
16431  printf(" Form the cavity of a missing region.\n");
16432  }
16433  // Mark this edge to avoid testing it later.
16434  markedge(*searchtet);
16435  crossedges->newindex((void **) &parytet);
16436  *parytet = *searchtet;
16437 
16438  invalidflag = 0;
16439  // Collect all crossing tets. Each cross tet is saved in the standard
16440  // form [d,e,#,#], where [d,e] is a crossing edge, d lies below R.
16441  // NEITHER d NOR e is a vertex of R (!pmarktested).
16442  for (i = 0; i < crossedges->objects && !invalidflag; i++) {
16443  // Get a crossing edge [d,e,#,#].
16444  searchtet = (triface *) fastlookup(crossedges, i);
16445  // Sort vertices into the bottom and top arrays.
16446  pd = org(*searchtet);
16447  if (!pinfected(pd)) {
16448  pinfect(pd);
16449  botpoints->newindex((void **) &parypt);
16450  *parypt = pd;
16451  }
16452  pe = dest(*searchtet);
16453  if (!pinfected(pe)) {
16454  pinfect(pe);
16455  toppoints->newindex((void **) &parypt);
16456  *parypt = pe;
16457  }
16458 
16459  // All tets sharing this edge are crossing tets.
16460  spintet = *searchtet;
16461  while (1) {
16462  if (!infected(spintet)) {
16463  infect(spintet);
16464  crosstets->newindex((void **) &parytet);
16465  *parytet = spintet;
16466  }
16467  // Go to the next crossing tet.
16468  fnextself(spintet);
16469  if (spintet.tet == searchtet->tet) break;
16470  } // while (1)
16471 
16472  // Detect new crossing edges.
16473  spintet = *searchtet;
16474  while (1) {
16475  // spintet is [d,e,a,#], where d lies below R, and e lies above R.
16476  pa = apex(spintet);
16477  if (pa != dummypoint) {
16478  if (!pmarktested(pa)) {
16479  // There exists a crossing edge, either [e,a] or [a,d]. First check
16480  // if the crossing edge has already be added, i.e.,to check if one
16481  // of the tetrahedron at this edge has been marked.
16482  testflag = true;
16483  for (j = 0; j < 2 && testflag; j++) {
16484  if (j == 0) {
16485  enext(spintet, neightet);
16486  } else {
16487  eprev(spintet, neightet);
16488  }
16489  while (1) {
16490  if (edgemarked(neightet)) {
16491  // This crossing edge has already been tested. Skip it.
16492  testflag = false;
16493  break;
16494  }
16495  fnextself(neightet);
16496  if (neightet.tet == spintet.tet) break;
16497  }
16498  } // j
16499  if (testflag) {
16500  // Test if [e,a] or [a,d] intersects R.
16501  // Do a brute-force search in the set of subfaces of R. Slow!
16502  // Need to be improved!
16503  pd = org(spintet);
16504  pe = dest(spintet);
16505  for (k = 0; k < missingshs->objects; k++) {
16506  parysh = (face *) fastlookup(missingshs, k);
16507  intflag = tri_edge_test(sorg(*parysh), sdest(*parysh),
16508  sapex(*parysh), pe, pa, NULL, 1, types, poss);
16509  if (intflag > 0) {
16510  // Found intersection. 'a' lies below R.
16511  if (intflag == 2) {
16512  enext(spintet, neightet);
16513  if ((types[0] == (int) ACROSSFACE) ||
16514  (types[0] == (int) ACROSSEDGE)) {
16515  // Only this case is valid.
16516  } else {
16517  // A non-valid intersection. Maybe a PLC problem.
16518  invalidflag = 1;
16519  }
16520  } else {
16521  // Coplanar intersection. Maybe a PLC problem.
16522  invalidflag = 1;
16523  }
16524  break;
16525  }
16526  intflag = tri_edge_test(sorg(*parysh), sdest(*parysh),
16527  sapex(*parysh), pa, pd, NULL, 1, types, poss);
16528  if (intflag > 0) {
16529  // Found intersection. 'a' lies above R.
16530  if (intflag == 2) {
16531  eprev(spintet, neightet);
16532  if ((types[0] == (int) ACROSSFACE) ||
16533  (types[0] == (int) ACROSSEDGE)) {
16534  // Only this case is valid.
16535  } else {
16536  // A non-valid intersection. Maybe a PLC problem.
16537  invalidflag = 1;
16538  }
16539  } else {
16540  // Coplanar intersection. Maybe a PLC problem.
16541  invalidflag = 1;
16542  }
16543  break;
16544  }
16545  } // k
16546  if (k < missingshs->objects) {
16547  // Found a pair of triangle - edge intersection.
16548  if (invalidflag) {
16549  break; // the while (1) loop
16550  }
16551  // Adjust the edge direction, so that its origin lies below R,
16552  // and its destination lies above R.
16553  esymself(neightet);
16554  // This edge may be a segment.
16555  if (issubseg(neightet)) {
16556  report_selfint_face(sorg(*parysh), sdest(*parysh),
16557  sapex(*parysh),parysh,&neightet,intflag,types,poss);
16558  }
16559  // Check if it is an edge of a subface.
16560  chkface = neightet;
16561  while (1) {
16562  if (issubface(chkface)) break;
16563  fsymself(chkface);
16564  if (chkface.tet == neightet.tet) break;
16565  }
16566  if (issubface(chkface)) {
16567  // Two subfaces are intersecting.
16568  report_selfint_face(sorg(*parysh), sdest(*parysh),
16569  sapex(*parysh),parysh,&chkface,intflag,types,poss);
16570  }
16571 
16572  // Mark this edge to avoid testing it again.
16573  markedge(neightet);
16574  crossedges->newindex((void **) &parytet);
16575  *parytet = neightet;
16576  } else {
16577  // No intersection is found. It may be a PLC problem.
16578  invalidflag = 1;
16579  break; // the while (1) loop
16580  } // if (k == missingshs->objects)
16581  } // if (testflag)
16582  }
16583  } // if (pa != dummypoint)
16584  // Go to the next crossing tet.
16585  fnextself(spintet);
16586  if (spintet.tet == searchtet->tet) break;
16587  } // while (1)
16588  } // i
16589 
16590  // Unmark all marked edges.
16591  for (i = 0; i < crossedges->objects; i++) {
16592  searchtet = (triface *) fastlookup(crossedges, i);
16593  unmarkedge(*searchtet);
16594  }
16595  crossedges->restart();
16596 
16597 
16598  if (invalidflag) {
16599  // Unmark all collected tets.
16600  for (i = 0; i < crosstets->objects; i++) {
16601  searchtet = (triface *) fastlookup(crosstets, i);
16602  uninfect(*searchtet);
16603  }
16604  // Unmark all collected vertices.
16605  for (i = 0; i < botpoints->objects; i++) {
16606  parypt = (point *) fastlookup(botpoints, i);
16607  puninfect(*parypt);
16608  }
16609  for (i = 0; i < toppoints->objects; i++) {
16610  parypt = (point *) fastlookup(toppoints, i);
16611  puninfect(*parypt);
16612  }
16613  crosstets->restart();
16614  botpoints->restart();
16615  toppoints->restart();
16616 
16617  // Randomly split an interior edge of R.
16618  i = randomnation(missingshs->objects - 1);
16619  recentsh = * (face *) fastlookup(missingshs, i);
16620  return false;
16621  }
16622 
16623  if (b->verbose > 2) {
16624  printf(" Formed cavity: %ld (%ld) cross tets (edges).\n",
16625  crosstets->objects, crossedges->objects);
16626  }
16627 
16628  // Collect the top and bottom faces and the middle vertices. Since all top
16629  // and bottom vertices have been infected. Uninfected vertices must be
16630  // middle vertices (i.e., the vertices of R).
16631  // NOTE 1: Hull tets may be collected. Process them as a normal one.
16632  // NOTE 2: Some previously recovered subfaces may be completely inside the
16633  // cavity. In such case, we remove these subfaces from the cavity and put
16634  // them into 'subfacstack'. They will be recovered later.
16635  // NOTE 3: Some segments may be completely inside the cavity, e.g., they
16636  // attached to a subface which is inside the cavity. Such segments are
16637  // put in 'subsegstack'. They will be recovered later.
16638  // NOTE4 : The interior subfaces and segments mentioned in NOTE 2 and 3
16639  // are identified in the routine "carvecavity()".
16640 
16641  for (i = 0; i < crosstets->objects; i++) {
16642  searchtet = (triface *) fastlookup(crosstets, i);
16643  // searchtet is [d,e,a,b].
16644  eorgoppo(*searchtet, spintet);
16645  fsym(spintet, neightet); // neightet is [a,b,e,#]
16646  if (!infected(neightet)) {
16647  // A top face.
16648  topfaces->newindex((void **) &parytet);
16649  *parytet = neightet;
16650  }
16651  edestoppo(*searchtet, spintet);
16652  fsym(spintet, neightet); // neightet is [b,a,d,#]
16653  if (!infected(neightet)) {
16654  // A bottom face.
16655  botfaces->newindex((void **) &parytet);
16656  *parytet = neightet;
16657  }
16658  // Add middle vertices if there are (skip dummypoint).
16659  pa = org(neightet);
16660  if (!pinfected(pa)) {
16661  if (pa != dummypoint) {
16662  pinfect(pa);
16663  botpoints->newindex((void **) &parypt);
16664  *parypt = pa;
16665  toppoints->newindex((void **) &parypt);
16666  *parypt = pa;
16667  }
16668  }
16669  pa = dest(neightet);
16670  if (!pinfected(pa)) {
16671  if (pa != dummypoint) {
16672  pinfect(pa);
16673  botpoints->newindex((void **) &parypt);
16674  *parypt = pa;
16675  toppoints->newindex((void **) &parypt);
16676  *parypt = pa;
16677  }
16678  }
16679  } // i
16680 
16681  // Uninfect all collected top, bottom, and middle vertices.
16682  for (i = 0; i < toppoints->objects; i++) {
16683  parypt = (point *) fastlookup(toppoints, i);
16684  puninfect(*parypt);
16685  }
16686  for (i = 0; i < botpoints->objects; i++) {
16687  parypt = (point *) fastlookup(botpoints, i);
16688  puninfect(*parypt);
16689  }
16690  cavitycount++;
16691 
16692  return true;
16693 }
16694 
16696 // //
16697 // delaunizecavity() Fill a cavity by Delaunay tetrahedra. //
16698 // //
16699 // The cavity C to be tetrahedralized is the top or bottom part of a whole //
16700 // cavity. 'cavfaces' contains the boundary faces of C. NOTE: faces in 'cav- //
16701 // faces' do not form a closed polyhedron. The "open" side are subfaces of //
16702 // the missing facet. These faces will be recovered later in fillcavity(). //
16703 // //
16704 // This routine first constructs the DT of the vertices. Then it identifies //
16705 // the half boundary faces of the cavity in DT. Possiblely the cavity C will //
16706 // be enlarged. //
16707 // //
16708 // The DT is returned in 'newtets'. //
16709 // //
16711 
16712 void tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces,
16713  arraypool *cavshells, arraypool *newtets,
16714  arraypool *crosstets, arraypool *misfaces)
16715 {
16716  triface searchtet, neightet, *parytet, *parytet1;
16717  face tmpsh, *parysh;
16718  point pa, pb, pc, pd, pt[3], *parypt;
16719  insertvertexflags ivf;
16720  REAL ori;
16721  long baknum, bakhullsize;
16722  int bakchecksubsegflag, bakchecksubfaceflag;
16723  int t1ver;
16724  int i, j;
16725 
16726  if (b->verbose > 2) {
16727  printf(" Delaunizing cavity: %ld points, %ld faces.\n",
16728  cavpoints->objects, cavfaces->objects);
16729  }
16730  // Remember the current number of crossing tets. It may be enlarged later.
16731  baknum = crosstets->objects;
16732  bakhullsize = hullsize;
16733  bakchecksubsegflag = checksubsegflag;
16734  bakchecksubfaceflag = checksubfaceflag;
16735  hullsize = 0l;
16736  checksubsegflag = 0;
16737  checksubfaceflag = 0;
16738  b->verbose--; // Suppress informations for creating Delaunay tetra.
16739  b->plc = 0; // Do not check near vertices.
16740 
16741  ivf.bowywat = 1; // Use Bowyer-Watson algorithm.
16742 
16743  // Get four non-coplanar points (no dummypoint).
16744  pa = pb = pc = NULL;
16745  for (i = 0; i < cavfaces->objects; i++) {
16746  parytet = (triface *) fastlookup(cavfaces, i);
16747  parytet->ver = epivot[parytet->ver];
16748  if (apex(*parytet) != dummypoint) {
16749  pa = org(*parytet);
16750  pb = dest(*parytet);
16751  pc = apex(*parytet);
16752  break;
16753  }
16754  }
16755  pd = NULL;
16756  for (; i < cavfaces->objects; i++) {
16757  parytet = (triface *) fastlookup(cavfaces, i);
16758  pt[0] = org(*parytet);
16759  pt[1] = dest(*parytet);
16760  pt[2] = apex(*parytet);
16761  for (j = 0; j < 3; j++) {
16762  if (pt[j] != dummypoint) { // Do not include a hull point.
16763  ori = orient3d(pa, pb, pc, pt[j]);
16764  if (ori != 0) {
16765  pd = pt[j];
16766  if (ori > 0) { // Swap pa and pb.
16767  pt[j] = pa; pa = pb; pb = pt[j];
16768  }
16769  break;
16770  }
16771  }
16772  }
16773  if (pd != NULL) break;
16774  }
16775 
16776  // Create an init DT.
16777  initialdelaunay(pa, pb, pc, pd);
16778 
16779  // Incrementally insert the vertices (duplicated vertices are ignored).
16780  for (i = 0; i < cavpoints->objects; i++) {
16781  pt[0] = * (point *) fastlookup(cavpoints, i);
16782  searchtet = recenttet;
16783  ivf.iloc = (int) OUTSIDE;
16784  insertpoint(pt[0], &searchtet, NULL, NULL, &ivf);
16785  }
16786 
16787  if (b->verbose > 2) {
16788  printf(" Identifying %ld boundary faces of the cavity.\n",
16789  cavfaces->objects);
16790  }
16791 
16792  while (1) {
16793 
16794  // Identify boundary faces. Mark interior tets. Save missing faces.
16795  for (i = 0; i < cavfaces->objects; i++) {
16796  parytet = (triface *) fastlookup(cavfaces, i);
16797  // Skip an interior face (due to the enlargement of the cavity).
16798  if (infected(*parytet)) continue;
16799  parytet->ver = epivot[parytet->ver];
16800  pt[0] = org(*parytet);
16801  pt[1] = dest(*parytet);
16802  pt[2] = apex(*parytet);
16803  // Create a temp subface.
16804  makeshellface(subfaces, &tmpsh);
16805  setshvertices(tmpsh, pt[0], pt[1], pt[2]);
16806  // Insert tmpsh in DT.
16807  searchtet.tet = NULL;
16808  if (scoutsubface(&tmpsh, &searchtet, 0)) { // shflag = 0
16809  // Inserted! 'tmpsh' must face toward the inside of the cavity.
16810  // Remember the boundary tet (outside the cavity) in tmpsh
16811  // (use the adjacent tet slot).
16812  tmpsh.sh[0] = (shellface) encode(*parytet);
16813  // Save this subface.
16814  cavshells->newindex((void **) &parysh);
16815  *parysh = tmpsh;
16816  }
16817  else {
16818  // This boundary face is missing.
16819  shellfacedealloc(subfaces, tmpsh.sh);
16820  // Save this face in list.
16821  misfaces->newindex((void **) &parytet1);
16822  *parytet1 = *parytet;
16823  }
16824  } // i
16825 
16826  if (misfaces->objects > 0) {
16827  if (b->verbose > 2) {
16828  printf(" Enlarging the cavity. %ld missing bdry faces\n",
16829  misfaces->objects);
16830  }
16831 
16832  // Removing all temporary subfaces.
16833  for (i = 0; i < cavshells->objects; i++) {
16834  parysh = (face *) fastlookup(cavshells, i);
16835  stpivot(*parysh, neightet);
16836  tsdissolve(neightet); // Detach it from adj. tets.
16837  fsymself(neightet);
16838  tsdissolve(neightet);
16839  shellfacedealloc(subfaces, parysh->sh);
16840  }
16841  cavshells->restart();
16842 
16843  // Infect the points which are of the cavity.
16844  for (i = 0; i < cavpoints->objects; i++) {
16845  pt[0] = * (point *) fastlookup(cavpoints, i);
16846  pinfect(pt[0]); // Mark it as inserted.
16847  }
16848 
16849  // Enlarge the cavity.
16850  for (i = 0; i < misfaces->objects; i++) {
16851  // Get a missing face.
16852  parytet = (triface *) fastlookup(misfaces, i);
16853  if (!infected(*parytet)) {
16854  // Put it into crossing tet list.
16855  infect(*parytet);
16856  crosstets->newindex((void **) &parytet1);
16857  *parytet1 = *parytet;
16858  // Insert the opposite point if it is not in DT.
16859  pd = oppo(*parytet);
16860  if (!pinfected(pd)) {
16861  searchtet = recenttet;
16862  ivf.iloc = (int) OUTSIDE;
16863  insertpoint(pd, &searchtet, NULL, NULL, &ivf);
16864  pinfect(pd);
16865  cavpoints->newindex((void **) &parypt);
16866  *parypt = pd;
16867  }
16868  // Add three opposite faces into the boundary list.
16869  for (j = 0; j < 3; j++) {
16870  esym(*parytet, neightet);
16871  fsymself(neightet);
16872  if (!infected(neightet)) {
16873  cavfaces->newindex((void **) &parytet1);
16874  *parytet1 = neightet;
16875  }
16876  enextself(*parytet);
16877  } // j
16878  } // if (!infected(parytet))
16879  } // i
16880 
16881  // Uninfect the points which are of the cavity.
16882  for (i = 0; i < cavpoints->objects; i++) {
16883  pt[0] = * (point *) fastlookup(cavpoints, i);
16884  puninfect(pt[0]);
16885  }
16886 
16887  misfaces->restart();
16888  continue;
16889  } // if (misfaces->objects > 0)
16890 
16891  break;
16892 
16893  } // while (1)
16894 
16895  // Collect all tets of the DT. All new tets are marktested.
16896  marktest(recenttet);
16897  newtets->newindex((void **) &parytet);
16898  *parytet = recenttet;
16899  for (i = 0; i < newtets->objects; i++) {
16900  searchtet = * (triface *) fastlookup(newtets, i);
16901  for (j = 0; j < 4; j++) {
16902  decode(searchtet.tet[j], neightet);
16903  if (!marktested(neightet)) {
16904  marktest(neightet);
16905  newtets->newindex((void **) &parytet);
16906  *parytet = neightet;
16907  }
16908  }
16909  }
16910 
16911  cavpoints->restart();
16912  cavfaces->restart();
16913 
16914  if (crosstets->objects > baknum) {
16915  // The cavity has been enlarged.
16916  cavityexpcount++;
16917  }
16918 
16919  // Restore the original values.
16920  hullsize = bakhullsize;
16921  checksubsegflag = bakchecksubsegflag;
16922  checksubfaceflag = bakchecksubfaceflag;
16923  b->verbose++;
16924  b->plc = 1;
16925 }
16926 
16928 // //
16929 // fillcavity() Fill new tets into the cavity. //
16930 // //
16931 // The new tets are stored in two disjoint sets(which share the same facet). //
16932 // 'topfaces' and 'botfaces' are the boundaries of these two sets, respect- //
16933 // ively. 'midfaces' is empty on input, and will store faces in the facet. //
16934 // //
16935 // Important: This routine assumes all vertices of the missing region R are //
16936 // marktested, i.e., pmarktested(p) returns true. //
16937 // //
16939 
16940 bool tetgenmesh::fillcavity(arraypool* topshells, arraypool* botshells,
16941  arraypool* midfaces, arraypool* missingshs,
16942  arraypool* topnewtets, arraypool* botnewtets,
16943  triface* crossedge)
16944 {
16945  arraypool *cavshells;
16946  triface bdrytet, neightet, *parytet;
16947  triface searchtet, spintet;
16948  face *parysh;
16949  face checkseg;
16950  point pa, pb, pc;
16951  bool mflag;
16952  int t1ver;
16953  int i, j;
16954 
16955  // Connect newtets to tets outside the cavity. These connections are needed
16956  // for identifying the middle faces (which belong to R).
16957  for (j = 0; j < 2; j++) {
16958  cavshells = (j == 0 ? topshells : botshells);
16959  if (cavshells != NULL) {
16960  for (i = 0; i < cavshells->objects; i++) {
16961  // Get a temp subface.
16962  parysh = (face *) fastlookup(cavshells, i);
16963  // Get the boundary tet outside the cavity (saved in sh[0]).
16964  decode(parysh->sh[0], bdrytet);
16965  pa = org(bdrytet);
16966  pb = dest(bdrytet);
16967  pc = apex(bdrytet);
16968  // Get the adjacent new tet inside the cavity.
16969  stpivot(*parysh, neightet);
16970  // Mark neightet as an interior tet of this cavity.
16971  infect(neightet);
16972  // Connect the two tets (the old connections are replaced).
16973  bond(bdrytet, neightet);
16974  tsdissolve(neightet); // Clear the pointer to tmpsh.
16975  // Update the point-to-tets map.
16976  setpoint2tet(pa, (tetrahedron) neightet.tet);
16977  setpoint2tet(pb, (tetrahedron) neightet.tet);
16978  setpoint2tet(pc, (tetrahedron) neightet.tet);
16979  } // i
16980  } // if (cavshells != NULL)
16981  } // j
16982 
16983  if (crossedge != NULL) {
16984  // Glue top and bottom tets at their common facet.
16985  triface toptet, bottet, spintet, *midface;
16986  point pd, pe;
16987  REAL ori;
16988  int types[2], poss[4];
16989  int interflag;
16990  int bflag;
16991 
16992  mflag = false;
16993  pd = org(*crossedge);
16994  pe = dest(*crossedge);
16995 
16996  // Search the first (middle) face in R.
16997  // Since R may be non-convex, we must make sure that the face is in the
16998  // interior of R. We search a face in 'topnewtets' whose three vertices
16999  // are on R and it intersects 'crossedge' in its interior. Then search
17000  // a matching face in 'botnewtets'.
17001  for (i = 0; i < topnewtets->objects && !mflag; i++) {
17002  searchtet = * (triface *) fastlookup(topnewtets, i);
17003  for (searchtet.ver = 0; searchtet.ver < 4 && !mflag; searchtet.ver++) {
17004  pa = org(searchtet);
17005  if (pmarktested(pa)) {
17006  pb = dest(searchtet);
17007  if (pmarktested(pb)) {
17008  pc = apex(searchtet);
17009  if (pmarktested(pc)) {
17010  // Check if this face intersects [d,e].
17011  interflag = tri_edge_test(pa,pb,pc,pd,pe,NULL,1,types,poss);
17012  if (interflag == 2) {
17013  // They intersect at a single point. Found.
17014  toptet = searchtet;
17015  // The face lies in the interior of R.
17016  // Get the tet (in topnewtets) which lies above R.
17017  ori = orient3d(pa, pb, pc, pd);
17018  if (ori < 0) {
17019  fsymself(toptet);
17020  pa = org(toptet);
17021  pb = dest(toptet);
17022  } else if (ori == 0) {
17023  terminatetetgen(this, 2);
17024  }
17025  // Search the face [b,a,c] in 'botnewtets'.
17026  for (j = 0; j < botnewtets->objects; j++) {
17027  neightet = * (triface *) fastlookup(botnewtets, j);
17028  // Is neightet contains 'b'.
17029  if ((point) neightet.tet[4] == pb) {
17030  neightet.ver = 11;
17031  } else if ((point) neightet.tet[5] == pb) {
17032  neightet.ver = 3;
17033  } else if ((point) neightet.tet[6] == pb) {
17034  neightet.ver = 7;
17035  } else if ((point) neightet.tet[7] == pb) {
17036  neightet.ver = 0;
17037  } else {
17038  continue;
17039  }
17040  // Is the 'neightet' contains edge [b,a].
17041  if (dest(neightet) == pa) {
17042  // 'neightet' is just the edge.
17043  } else if (apex(neightet) == pa) {
17044  eprevesymself(neightet);
17045  } else if (oppo(neightet) == pa) {
17046  esymself(neightet);
17047  enextself(neightet);
17048  } else {
17049  continue;
17050  }
17051  // Is 'neightet' the face [b,a,c].
17052  if (apex(neightet) == pc) {
17053  bottet = neightet;
17054  mflag = true;
17055  break;
17056  }
17057  } // j
17058  } // if (interflag == 2)
17059  } // pc
17060  } // pb
17061  } // pa
17062  } // toptet.ver
17063  } // i
17064 
17065  if (mflag) {
17066  // Found a pair of matched faces in 'toptet' and 'bottet'.
17067  bond(toptet, bottet);
17068  // Both are interior tets.
17069  infect(toptet);
17070  infect(bottet);
17071  // Add this face into search list.
17072  markface(toptet);
17073  midfaces->newindex((void **) &parytet);
17074  *parytet = toptet;
17075  } else {
17076  // No pair of 'toptet' and 'bottet'.
17077  toptet.tet = NULL;
17078  // Randomly split an interior edge of R.
17079  i = randomnation(missingshs->objects - 1);
17080  recentsh = * (face *) fastlookup(missingshs, i);
17081  }
17082 
17083  // Find other middle faces, connect top and bottom tets.
17084  for (i = 0; i < midfaces->objects && mflag; i++) {
17085  // Get a matched middle face [a, b, c]
17086  midface = (triface *) fastlookup(midfaces, i);
17087  // Check the neighbors at the edges of this face.
17088  for (j = 0; j < 3 && mflag; j++) {
17089  toptet = *midface;
17090  bflag = false;
17091  while (1) {
17092  // Go to the next face in the same tet.
17093  esymself(toptet);
17094  pc = apex(toptet);
17095  if (pmarktested(pc)) {
17096  break; // Find a subface.
17097  }
17098  if (pc == dummypoint) {
17099  terminatetetgen(this, 2); // Check this case.
17100  break; // Find a subface.
17101  }
17102  // Go to the adjacent tet.
17103  fsymself(toptet);
17104  // Do we walk outside the cavity?
17105  if (!marktested(toptet)) {
17106  // Yes, the adjacent face is not a middle face.
17107  bflag = true; break;
17108  }
17109  }
17110  if (!bflag) {
17111  if (!facemarked(toptet)) {
17112  fsym(*midface, bottet);
17113  spintet = bottet;
17114  while (1) {
17115  esymself(bottet);
17116  pd = apex(bottet);
17117  if (pd == pc) break; // Face matched.
17118  fsymself(bottet);
17119  if (bottet.tet == spintet.tet) {
17120  // Not found a matched bottom face.
17121  mflag = false;
17122  break;
17123  }
17124  } // while (1)
17125  if (mflag) {
17126  if (marktested(bottet)) {
17127  // Connect two tets together.
17128  bond(toptet, bottet);
17129  // Both are interior tets.
17130  infect(toptet);
17131  infect(bottet);
17132  // Add this face into list.
17133  markface(toptet);
17134  midfaces->newindex((void **) &parytet);
17135  *parytet = toptet;
17136  }
17137  else {
17138  // The 'bottet' is not inside the cavity!
17139  terminatetetgen(this, 2); // Check this case
17140  }
17141  } else { // mflag == false
17142  // Adjust 'toptet' and 'bottet' to be the crossing edges.
17143  fsym(*midface, bottet);
17144  spintet = bottet;
17145  while (1) {
17146  esymself(bottet);
17147  pd = apex(bottet);
17148  if (pmarktested(pd)) {
17149  // assert(pd != pc);
17150  // Let 'toptet' be [a,b,c,#], and 'bottet' be [b,a,d,*].
17151  // Adjust 'toptet' and 'bottet' to be the crossing edges.
17152  // Test orient3d(b,c,#,d).
17153  ori = orient3d(dest(toptet), pc, oppo(toptet), pd);
17154  if (ori < 0) {
17155  // Edges [a,d] and [b,c] cross each other.
17156  enextself(toptet); // [b,c]
17157  enextself(bottet); // [a,d]
17158  } else if (ori > 0) {
17159  // Edges [a,c] and [b,d] cross each other.
17160  eprevself(toptet); // [c,a]
17161  eprevself(bottet); // [d,b]
17162  } else {
17163  // b,c,#,and d are coplanar!.
17164  terminatetetgen(this, 2); //assert(0);
17165  }
17166  break; // Not matched
17167  }
17168  fsymself(bottet);
17169  }
17170  } // if (!mflag)
17171  } // if (!facemarked(toptet))
17172  } // if (!bflag)
17173  enextself(*midface);
17174  } // j
17175  } // i
17176 
17177  if (mflag) {
17178  if (b->verbose > 2) {
17179  printf(" Found %ld middle subfaces.\n", midfaces->objects);
17180  }
17181  face oldsh, newsh, casout, casin, neighsh;
17182 
17183  oldsh = * (face *) fastlookup(missingshs, 0);
17184 
17185  // Create new subfaces to fill the region R.
17186  for (i = 0; i < midfaces->objects; i++) {
17187  // Get a matched middle face [a, b, c]
17188  midface = (triface *) fastlookup(midfaces, i);
17189  unmarkface(*midface);
17190  makeshellface(subfaces, &newsh);
17191  setsorg(newsh, org(*midface));
17192  setsdest(newsh, dest(*midface));
17193  setsapex(newsh, apex(*midface));
17194  // The new subface gets its markers from the old one.
17195  setshellmark(newsh, shellmark(oldsh));
17196  if (checkconstraints) {
17197  setareabound(newsh, areabound(oldsh));
17198  }
17199  if (useinsertradius) {
17200  setfacetindex(newsh, getfacetindex(oldsh));
17201  }
17202  // Connect the new subface to adjacent tets.
17203  tsbond(*midface, newsh);
17204  fsym(*midface, neightet);
17205  sesymself(newsh);
17206  tsbond(neightet, newsh);
17207  }
17208 
17209  // Connect new subfaces together and to the bdry of R.
17210  // Delete faked segments.
17211  for (i = 0; i < midfaces->objects; i++) {
17212  // Get a matched middle face [a, b, c]
17213  midface = (triface *) fastlookup(midfaces, i);
17214  for (j = 0; j < 3; j++) {
17215  tspivot(*midface, newsh);
17216  spivot(newsh, casout);
17217  if (casout.sh == NULL) {
17218  // Search its neighbor.
17219  fnext(*midface, searchtet);
17220  while (1) {
17221  // (1) First check if this side is a bdry edge of R.
17222  tsspivot1(searchtet, checkseg);
17223  if (checkseg.sh != NULL) {
17224  // It's a bdry edge of R.
17225  // Get the old subface.
17226  checkseg.shver = 0;
17227  spivot(checkseg, oldsh);
17228  if (sinfected(checkseg)) {
17229  // It's a faked segment. Delete it.
17230  spintet = searchtet;
17231  while (1) {
17232  tssdissolve1(spintet);
17233  fnextself(spintet);
17234  if (spintet.tet == searchtet.tet) break;
17235  }
17236  shellfacedealloc(subsegs, checkseg.sh);
17237  ssdissolve(oldsh);
17238  checkseg.sh = NULL;
17239  }
17240  spivot(oldsh, casout);
17241  if (casout.sh != NULL) {
17242  casin = casout;
17243  if (checkseg.sh != NULL) {
17244  // Make sure that the subface has the right ori at the
17245  // segment.
17246  checkseg.shver = 0;
17247  if (sorg(newsh) != sorg(checkseg)) {
17248  sesymself(newsh);
17249  }
17250  spivot(casin, neighsh);
17251  while (neighsh.sh != oldsh.sh) {
17252  casin = neighsh;
17253  spivot(casin, neighsh);
17254  }
17255  }
17256  sbond1(newsh, casout);
17257  sbond1(casin, newsh);
17258  }
17259  if (checkseg.sh != NULL) {
17260  ssbond(newsh, checkseg);
17261  }
17262  break;
17263  } // if (checkseg.sh != NULL)
17264  // (2) Second check if this side is an interior edge of R.
17265  tspivot(searchtet, neighsh);
17266  if (neighsh.sh != NULL) {
17267  // Found an adjacent subface of newsh (an interior edge).
17268  sbond(newsh, neighsh);
17269  break;
17270  }
17271  fnextself(searchtet);
17272  } // while (1)
17273  } // if (casout.sh == NULL)
17274  enextself(*midface);
17275  } // j
17276  } // i
17277 
17278  // Delete old subfaces.
17279  for (i = 0; i < missingshs->objects; i++) {
17280  parysh = (face *) fastlookup(missingshs, i);
17281  shellfacedealloc(subfaces, parysh->sh);
17282  }
17283  } else {
17284  if (toptet.tet != NULL) {
17285  // Faces at top and bottom are not matched.
17286  // Choose a Steiner point in R.
17287  // Split one of the crossing edges.
17288  pa = org(toptet);
17289  pb = dest(toptet);
17290  pc = org(bottet);
17291  pd = dest(bottet);
17292  // Search an edge in R which is either [a,b] or [c,d].
17293  // Reminder: Subfaces in this list 'missingshs', except the first
17294  // one, represents an interior edge of R.
17295  parysh = NULL; // Avoid a warning in MSVC
17296  for (i = 1; i < missingshs->objects; i++) {
17297  parysh = (face *) fastlookup(missingshs, i);
17298  if (((sorg(*parysh) == pa) && (sdest(*parysh) == pb)) ||
17299  ((sorg(*parysh) == pb) && (sdest(*parysh) == pa))) break;
17300  if (((sorg(*parysh) == pc) && (sdest(*parysh) == pd)) ||
17301  ((sorg(*parysh) == pd) && (sdest(*parysh) == pc))) break;
17302  }
17303  if (i < missingshs->objects) {
17304  // Found. Return it.
17305  recentsh = *parysh;
17306  } else {
17307  terminatetetgen(this, 2); //assert(0);
17308  }
17309  } else {
17310  //terminatetetgen(this, 2); // Report a bug
17311  }
17312  }
17313 
17314  midfaces->restart();
17315  } else {
17316  mflag = true;
17317  }
17318 
17319  // Delete the temp subfaces.
17320  for (j = 0; j < 2; j++) {
17321  cavshells = (j == 0 ? topshells : botshells);
17322  if (cavshells != NULL) {
17323  for (i = 0; i < cavshells->objects; i++) {
17324  parysh = (face *) fastlookup(cavshells, i);
17325  shellfacedealloc(subfaces, parysh->sh);
17326  }
17327  }
17328  }
17329 
17330  topshells->restart();
17331  if (botshells != NULL) {
17332  botshells->restart();
17333  }
17334 
17335  return mflag;
17336 }
17337 
17339 // //
17340 // carvecavity() Delete old tets and outer new tets of the cavity. //
17341 // //
17343 
17344 void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets,
17345  arraypool *botnewtets)
17346 {
17347  arraypool *newtets;
17348  shellface *sptr, *ssptr;
17349  triface *parytet, *pnewtet, newtet, neightet, spintet;
17350  face checksh, *parysh;
17351  face checkseg, *paryseg;
17352  int t1ver;
17353  int i, j;
17354 
17355  if (b->verbose > 2) {
17356  printf(" Carve cavity: %ld old tets.\n", crosstets->objects);
17357  }
17358 
17359  // First process subfaces and segments which are adjacent to the cavity.
17360  // They must be re-connected to new tets in the cavity.
17361  // Comment: It is possible that some subfaces and segments are completely
17362  // inside the cavity. This can happen even if the cavity is not enlarged.
17363  // Before deleting the old tets, find and queue all interior subfaces
17364  // and segments. They will be recovered later. 2010-05-06.
17365 
17366  // Collect all subfaces and segments which attached to the old tets.
17367  for (i = 0; i < crosstets->objects; i++) {
17368  parytet = (triface *) fastlookup(crosstets, i);
17369  if ((sptr = (shellface*) parytet->tet[9]) != NULL) {
17370  for (j = 0; j < 4; j++) {
17371  if (sptr[j]) {
17372  sdecode(sptr[j], checksh);
17373  if (!sinfected(checksh)) {
17374  sinfect(checksh);
17375  cavetetshlist->newindex((void **) &parysh);
17376  *parysh = checksh;
17377  }
17378  }
17379  } // j
17380  }
17381  if ((ssptr = (shellface*) parytet->tet[8]) != NULL) {
17382  for (j = 0; j < 6; j++) {
17383  if (ssptr[j]) {
17384  sdecode(ssptr[j], checkseg);
17385  // Skip a deleted segment (was a faked segment)
17386  if (checkseg.sh[3] != NULL) {
17387  if (!sinfected(checkseg)) {
17388  sinfect(checkseg);
17389  cavetetseglist->newindex((void **) &paryseg);
17390  *paryseg = checkseg;
17391  }
17392  }
17393  }
17394  } // j
17395  }
17396  } // i
17397 
17398  // Uninfect collected subfaces.
17399  for (i = 0; i < cavetetshlist->objects; i++) {
17400  parysh = (face *) fastlookup(cavetetshlist, i);
17401  suninfect(*parysh);
17402  }
17403  // Uninfect collected segments.
17404  for (i = 0; i < cavetetseglist->objects; i++) {
17405  paryseg = (face *) fastlookup(cavetetseglist, i);
17406  suninfect(*paryseg);
17407  }
17408 
17409  // Connect subfaces to new tets.
17410  for (i = 0; i < cavetetshlist->objects; i++) {
17411  parysh = (face *) fastlookup(cavetetshlist, i);
17412  // Get an adjacent tet at this subface.
17413  stpivot(*parysh, neightet);
17414  // Does this tet lie inside the cavity.
17415  if (infected(neightet)) {
17416  // Yes. Get the other adjacent tet at this subface.
17417  sesymself(*parysh);
17418  stpivot(*parysh, neightet);
17419  // Does this tet lie inside the cavity.
17420  if (infected(neightet)) {
17421  checksh = *parysh;
17422  stdissolve(checksh);
17423  caveencshlist->newindex((void **) &parysh);
17424  *parysh = checksh;
17425  }
17426  }
17427  if (!infected(neightet)) {
17428  // Found an outside tet. Re-connect this subface to a new tet.
17429  fsym(neightet, newtet);
17430  sesymself(*parysh);
17431  tsbond(newtet, *parysh);
17432  }
17433  } // i
17434 
17435 
17436  for (i = 0; i < cavetetseglist->objects; i++) {
17437  checkseg = * (face *) fastlookup(cavetetseglist, i);
17438  // Check if the segment is inside the cavity.
17439  sstpivot1(checkseg, neightet);
17440  spintet = neightet;
17441  while (1) {
17442  if (!infected(spintet)) {
17443  // This segment is on the boundary of the cavity.
17444  break;
17445  }
17446  fnextself(spintet);
17447  if (spintet.tet == neightet.tet) {
17448  sstdissolve1(checkseg);
17449  caveencseglist->newindex((void **) &paryseg);
17450  *paryseg = checkseg;
17451  break;
17452  }
17453  }
17454  if (!infected(spintet)) {
17455  // A boundary segment. Connect this segment to the new tets.
17456  sstbond1(checkseg, spintet);
17457  neightet = spintet;
17458  while (1) {
17459  tssbond1(spintet, checkseg);
17460  fnextself(spintet);
17461  if (spintet.tet == neightet.tet) break;
17462  }
17463  }
17464  } // i
17465 
17466 
17467  cavetetshlist->restart();
17468  cavetetseglist->restart();
17469 
17470  // Delete the old tets in cavity.
17471  for (i = 0; i < crosstets->objects; i++) {
17472  parytet = (triface *) fastlookup(crosstets, i);
17473  if (ishulltet(*parytet)) {
17474  hullsize--;
17475  }
17476  tetrahedrondealloc(parytet->tet);
17477  }
17478 
17479  crosstets->restart(); // crosstets will be re-used.
17480 
17481  // Collect new tets in cavity. Some new tets have already been found
17482  // (and infected) in the fillcavity(). We first collect them.
17483  for (j = 0; j < 2; j++) {
17484  newtets = (j == 0 ? topnewtets : botnewtets);
17485  if (newtets != NULL) {
17486  for (i = 0; i < newtets->objects; i++) {
17487  parytet = (triface *) fastlookup(newtets, i);
17488  if (infected(*parytet)) {
17489  crosstets->newindex((void **) &pnewtet);
17490  *pnewtet = *parytet;
17491  }
17492  } // i
17493  }
17494  } // j
17495 
17496  // Now we collect all new tets in cavity.
17497  for (i = 0; i < crosstets->objects; i++) {
17498  parytet = (triface *) fastlookup(crosstets, i);
17499  for (j = 0; j < 4; j++) {
17500  decode(parytet->tet[j], neightet);
17501  if (marktested(neightet)) { // Is it a new tet?
17502  if (!infected(neightet)) {
17503  // Find an interior tet.
17504  //assert((point) neightet.tet[7] != dummypoint); // SELF_CHECK
17505  infect(neightet);
17506  crosstets->newindex((void **) &pnewtet);
17507  *pnewtet = neightet;
17508  }
17509  }
17510  } // j
17511  } // i
17512 
17513  parytet = (triface *) fastlookup(crosstets, 0);
17514  recenttet = *parytet; // Remember a live handle.
17515 
17516  // Delete outer new tets.
17517  for (j = 0; j < 2; j++) {
17518  newtets = (j == 0 ? topnewtets : botnewtets);
17519  if (newtets != NULL) {
17520  for (i = 0; i < newtets->objects; i++) {
17521  parytet = (triface *) fastlookup(newtets, i);
17522  if (infected(*parytet)) {
17523  // This is an interior tet.
17524  uninfect(*parytet);
17525  unmarktest(*parytet);
17526  if (ishulltet(*parytet)) {
17527  hullsize++;
17528  }
17529  } else {
17530  // An outer tet. Delete it.
17531  tetrahedrondealloc(parytet->tet);
17532  }
17533  }
17534  }
17535  }
17536 
17537  crosstets->restart();
17538  topnewtets->restart();
17539  if (botnewtets != NULL) {
17540  botnewtets->restart();
17541  }
17542 }
17543 
17545 // //
17546 // restorecavity() Reconnect old tets and delete new tets of the cavity. //
17547 // //
17549 
17550 void tetgenmesh::restorecavity(arraypool *crosstets, arraypool *topnewtets,
17551  arraypool *botnewtets, arraypool *missingshbds)
17552 {
17553  triface *parytet, neightet, spintet;
17554  face *parysh;
17555  face checkseg;
17556  point *ppt;
17557  int t1ver;
17558  int i, j;
17559 
17560  // Reconnect crossing tets to cavity boundary.
17561  for (i = 0; i < crosstets->objects; i++) {
17562  parytet = (triface *) fastlookup(crosstets, i);
17563  parytet->ver = 0;
17564  for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
17565  fsym(*parytet, neightet);
17566  if (!infected(neightet)) {
17567  // Restore the old connections of tets.
17568  bond(*parytet, neightet);
17569  }
17570  }
17571  // Update the point-to-tet map.
17572  parytet->ver = 0;
17573  ppt = (point *) &(parytet->tet[4]);
17574  for (j = 0; j < 4; j++) {
17575  setpoint2tet(ppt[j], encode(*parytet));
17576  }
17577  }
17578 
17579  // Uninfect all crossing tets.
17580  for (i = 0; i < crosstets->objects; i++) {
17581  parytet = (triface *) fastlookup(crosstets, i);
17582  uninfect(*parytet);
17583  }
17584 
17585  // Remember a live handle.
17586  if (crosstets->objects > 0) {
17587  recenttet = * (triface *) fastlookup(crosstets, 0);
17588  }
17589 
17590  // Delete faked segments.
17591  for (i = 0; i < missingshbds->objects; i++) {
17592  parysh = (face *) fastlookup(missingshbds, i);
17593  sspivot(*parysh, checkseg);
17594  if (checkseg.sh[3] != NULL) {
17595  if (sinfected(checkseg)) {
17596  // It's a faked segment. Delete it.
17597  sstpivot1(checkseg, neightet);
17598  spintet = neightet;
17599  while (1) {
17600  tssdissolve1(spintet);
17601  fnextself(spintet);
17602  if (spintet.tet == neightet.tet) break;
17603  }
17604  shellfacedealloc(subsegs, checkseg.sh);
17605  ssdissolve(*parysh);
17606  //checkseg.sh = NULL;
17607  }
17608  }
17609  } // i
17610 
17611  // Delete new tets.
17612  for (i = 0; i < topnewtets->objects; i++) {
17613  parytet = (triface *) fastlookup(topnewtets, i);
17614  tetrahedrondealloc(parytet->tet);
17615  }
17616 
17617  if (botnewtets != NULL) {
17618  for (i = 0; i < botnewtets->objects; i++) {
17619  parytet = (triface *) fastlookup(botnewtets, i);
17620  tetrahedrondealloc(parytet->tet);
17621  }
17622  }
17623 
17624  crosstets->restart();
17625  topnewtets->restart();
17626  if (botnewtets != NULL) {
17627  botnewtets->restart();
17628  }
17629 }
17630 
17632 // //
17633 // flipcertify() Insert a crossing face into priority queue. //
17634 // //
17635 // A crossing face of a facet must have at least one top and one bottom ver- //
17636 // tex of the facet. //
17637 // //
17639 
17640 void tetgenmesh::flipcertify(triface *chkface,badface **pqueue,point plane_pa,
17641  point plane_pb, point plane_pc)
17642 {
17643  badface *parybf, *prevbf, *nextbf;
17644  triface neightet;
17645  face checksh;
17646  point p[5];
17647  REAL w[5];
17648  REAL insph, ori4;
17649  int topi, boti;
17650  int i;
17651 
17652  // Compute the flip time \tau.
17653  fsym(*chkface, neightet);
17654 
17655  p[0] = org(*chkface);
17656  p[1] = dest(*chkface);
17657  p[2] = apex(*chkface);
17658  p[3] = oppo(*chkface);
17659  p[4] = oppo(neightet);
17660 
17661  // Check if the face is a crossing face.
17662  topi = boti = 0;
17663  for (i = 0; i < 3; i++) {
17664  if (pmarktest2ed(p[i])) topi++;
17665  if (pmarktest3ed(p[i])) boti++;
17666  }
17667  if ((topi == 0) || (boti == 0)) {
17668  // It is not a crossing face.
17669  // return;
17670  for (i = 3; i < 5; i++) {
17671  if (pmarktest2ed(p[i])) topi++;
17672  if (pmarktest3ed(p[i])) boti++;
17673  }
17674  if ((topi == 0) || (boti == 0)) {
17675  // The two tets sharing at this face are on one side of the facet.
17676  // Check if this face is locally Delaunay (due to rounding error).
17677  if ((p[3] != dummypoint) && (p[4] != dummypoint)) {
17678  // Do not check it if it is a subface.
17679  tspivot(*chkface, checksh);
17680  if (checksh.sh == NULL) {
17681  insph = insphere_s(p[1], p[0], p[2], p[3], p[4]);
17682  if (insph > 0) {
17683  // Add the face into queue.
17684  if (b->verbose > 2) {
17685  printf(" A locally non-Delanay face (%d, %d, %d)-%d,%d\n",
17686  pointmark(p[0]), pointmark(p[1]), pointmark(p[2]),
17687  pointmark(p[3]), pointmark(p[4]));
17688  }
17689  parybf = (badface *) flippool->alloc();
17690  parybf->key = 0.; // tau = 0, do immediately.
17691  parybf->tt = *chkface;
17692  parybf->forg = p[0];
17693  parybf->fdest = p[1];
17694  parybf->fapex = p[2];
17695  parybf->foppo = p[3];
17696  parybf->noppo = p[4];
17697  // Add it at the top of the priority queue.
17698  if (*pqueue == NULL) {
17699  *pqueue = parybf;
17700  parybf->nextitem = NULL;
17701  } else {
17702  parybf->nextitem = *pqueue;
17703  *pqueue = parybf;
17704  }
17705  } // if (insph > 0)
17706  } // if (checksh.sh == NULL)
17707  }
17708  }
17709  return; // Test: omit this face.
17710  }
17711 
17712  // Decide the "height" for each point.
17713  for (i = 0; i < 5; i++) {
17714  if (pmarktest2ed(p[i])) {
17715  // A top point has a positive weight.
17716  w[i] = orient3dfast(plane_pa, plane_pb, plane_pc, p[i]);
17717  if (w[i] < 0) w[i] = -w[i];
17718  } else {
17719  w[i] = 0;
17720  }
17721  }
17722 
17723  insph = insphere(p[1], p[0], p[2], p[3], p[4]);
17724  ori4 = orient4d(p[1], p[0], p[2], p[3], p[4], w[1], w[0], w[2], w[3], w[4]);
17725  if (ori4 > 0) {
17726  // Add the face into queue.
17727  if (b->verbose > 2) {
17728  printf(" Insert face (%d, %d, %d) - %d, %d\n", pointmark(p[0]),
17729  pointmark(p[1]), pointmark(p[2]), pointmark(p[3]), pointmark(p[4]));
17730  }
17731 
17732  parybf = (badface *) flippool->alloc();
17733 
17734  parybf->key = -insph / ori4;
17735  parybf->tt = *chkface;
17736  parybf->forg = p[0];
17737  parybf->fdest = p[1];
17738  parybf->fapex = p[2];
17739  parybf->foppo = p[3];
17740  parybf->noppo = p[4];
17741 
17742  // Push the face into priority queue.
17743  //pq.push(bface);
17744  if (*pqueue == NULL) {
17745  *pqueue = parybf;
17746  parybf->nextitem = NULL;
17747  } else {
17748  // Search an item whose key is larger or equal to current key.
17749  prevbf = NULL;
17750  nextbf = *pqueue;
17751  //if (!b->flipinsert_random) { // Default use a priority queue.
17752  // Insert the item into priority queue.
17753  while (nextbf != NULL) {
17754  if (nextbf->key < parybf->key) {
17755  prevbf = nextbf;
17756  nextbf = nextbf->nextitem;
17757  } else {
17758  break;
17759  }
17760  }
17761  //} // if (!b->flipinsert_random)
17762  // Insert the new item between prev and next items.
17763  if (prevbf == NULL) {
17764  *pqueue = parybf;
17765  } else {
17766  prevbf->nextitem = parybf;
17767  }
17768  parybf->nextitem = nextbf;
17769  }
17770  } else if (ori4 == 0) {
17771 
17772  }
17773 }
17774 
17776 // //
17777 // flipinsertfacet() Insert a facet into a CDT by flips. //
17778 // //
17779 // The algorithm is described in Shewchuk's paper "Updating and Constructing //
17780 // Constrained Delaunay and Constrained Regular Triangulations by Flips", in //
17781 // Proc. 19th Ann. Symp. on Comput. Geom., 86--95, 2003. //
17782 // //
17783 // 'crosstets' contains the set of crossing tetrahedra (infected) of the //
17784 // facet. 'toppoints' and 'botpoints' are points lies above and below the //
17785 // facet, not on the facet. //
17786 // //
17788 
17789 void tetgenmesh::flipinsertfacet(arraypool *crosstets, arraypool *toppoints,
17790  arraypool *botpoints, arraypool *midpoints)
17791 {
17792  arraypool *crossfaces, *bfacearray;
17793  triface fliptets[6], baktets[2], fliptet, newface;
17794  triface neightet, *parytet;
17795  badface *pqueue;
17796  badface *popbf, bface;
17797  point plane_pa, plane_pb, plane_pc;
17798  point p1, p2, pd, pe;
17799  point *parypt;
17800  flipconstraints fc;
17801  REAL ori[3];
17802  int convcount, copcount;
17803  int flipflag, fcount;
17804  int n, i;
17805  long f23count, f32count, f44count;
17806  long totalfcount;
17807 
17808  f23count = flip23count;
17809  f32count = flip32count;
17810  f44count = flip44count;
17811 
17812  // Get three affinely independent vertices in the missing region R.
17813  calculateabovepoint(midpoints, &plane_pa, &plane_pb, &plane_pc);
17814 
17815  // Mark top and bottom points. Do not mark midpoints.
17816  for (i = 0; i < toppoints->objects; i++) {
17817  parypt = (point *) fastlookup(toppoints, i);
17818  if (!pmarktested(*parypt)) {
17819  pmarktest2(*parypt);
17820  }
17821  }
17822  for (i = 0; i < botpoints->objects; i++) {
17823  parypt = (point *) fastlookup(botpoints, i);
17824  if (!pmarktested(*parypt)) {
17825  pmarktest3(*parypt);
17826  }
17827  }
17828 
17829  // Collect crossing faces.
17830  crossfaces = cavetetlist; // Re-use array 'cavetetlist'.
17831 
17832  // Each crossing face contains at least one bottom vertex and
17833  // one top vertex.
17834  for (i = 0; i < crosstets->objects; i++) {
17835  parytet = (triface *) fastlookup(crosstets, i);
17836  fliptet = *parytet;
17837  for (fliptet.ver = 0; fliptet.ver < 4; fliptet.ver++) {
17838  fsym(fliptet, neightet);
17839  if (infected(neightet)) { // It is an interior face.
17840  if (!marktested(neightet)) { // It is an unprocessed face.
17841  crossfaces->newindex((void **) &parytet);
17842  *parytet = fliptet;
17843  }
17844  }
17845  }
17846  marktest(fliptet);
17847  }
17848 
17849  if (b->verbose > 1) {
17850  printf(" Found %ld crossing faces.\n", crossfaces->objects);
17851  }
17852 
17853  for (i = 0; i < crosstets->objects; i++) {
17854  parytet = (triface *) fastlookup(crosstets, i);
17855  unmarktest(*parytet);
17856  uninfect(*parytet);
17857  }
17858 
17859  // Initialize the priority queue.
17860  pqueue = NULL;
17861 
17862  for (i = 0; i < crossfaces->objects; i++) {
17863  parytet = (triface *) fastlookup(crossfaces, i);
17864  flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
17865  }
17866  crossfaces->restart();
17867 
17868  // The list for temporarily storing unflipable faces.
17869  bfacearray = new arraypool(sizeof(triface), 4);
17870 
17871 
17872  fcount = 0; // Count the number of flips.
17873 
17874  // Flip insert the facet.
17875  while (pqueue != NULL) {
17876 
17877  // Pop a face from the priority queue.
17878  popbf = pqueue;
17879  bface = *popbf;
17880  // Update the queue.
17881  pqueue = pqueue->nextitem;
17882  // Delete the popped item from the pool.
17883  flippool->dealloc((void *) popbf);
17884 
17885  if (!isdeadtet(bface.tt)) {
17886  if ((org(bface.tt) == bface.forg) && (dest(bface.tt) == bface.fdest) &&
17887  (apex(bface.tt) == bface.fapex) && (oppo(bface.tt) == bface.foppo)) {
17888  // It is still a crossing face of R.
17889  fliptet = bface.tt;
17890  fsym(fliptet, neightet);
17891  if (oppo(neightet) == bface.noppo) {
17892  pd = oppo(fliptet);
17893  pe = oppo(neightet);
17894 
17895  if (b->verbose > 2) {
17896  printf(" Get face (%d, %d, %d) - %d, %d, tau = %.17g\n",
17897  pointmark(bface.forg), pointmark(bface.fdest),
17898  pointmark(bface.fapex), pointmark(bface.foppo),
17899  pointmark(bface.noppo), bface.key);
17900  }
17901  flipflag = 0;
17902 
17903  // Check for which type of flip can we do.
17904  convcount = 3;
17905  copcount = 0;
17906  for (i = 0; i < 3; i++) {
17907  p1 = org(fliptet);
17908  p2 = dest(fliptet);
17909  ori[i] = orient3d(p1, p2, pd, pe);
17910  if (ori[i] < 0) {
17911  convcount--;
17912  //break;
17913  } else if (ori[i] == 0) {
17914  convcount--; // Possible 4-to-4 flip.
17915  copcount++;
17916  //break;
17917  }
17918  enextself(fliptet);
17919  }
17920 
17921  if (convcount == 3) {
17922  // A 2-to-3 flip is found.
17923  fliptets[0] = fliptet; // abcd, d may be the new vertex.
17924  fliptets[1] = neightet; // bace.
17925  flip23(fliptets, 1, &fc);
17926  // Put the link faces into check list.
17927  for (i = 0; i < 3; i++) {
17928  eprevesym(fliptets[i], newface);
17929  crossfaces->newindex((void **) &parytet);
17930  *parytet = newface;
17931  }
17932  for (i = 0; i < 3; i++) {
17933  enextesym(fliptets[i], newface);
17934  crossfaces->newindex((void **) &parytet);
17935  *parytet = newface;
17936  }
17937  flipflag = 1;
17938  } else if (convcount == 2) {
17939  //if (copcount <= 1) {
17940  // A 3-to-2 or 4-to-4 may be possible.
17941  // Get the edge which is locally non-convex or flat.
17942  for (i = 0; i < 3; i++) {
17943  if (ori[i] <= 0) break;
17944  enextself(fliptet);
17945  }
17946 
17947  // Collect tets sharing at this edge.
17948  esym(fliptet, fliptets[0]); // [b,a,d,c]
17949  n = 0;
17950  do {
17951  p1 = apex(fliptets[n]);
17952  if (!(pmarktested(p1) || pmarktest2ed(p1) || pmarktest3ed(p1))) {
17953  // This apex is not on the cavity. Hence the face does not
17954  // lie inside the cavity. Do not flip this edge.
17955  n = 1000; break;
17956  }
17957  fnext(fliptets[n], fliptets[n + 1]);
17958  n++;
17959  } while ((fliptets[n].tet != fliptet.tet) && (n < 5));
17960 
17961  if (n == 3) {
17962  // Found a 3-to-2 flip.
17963  flip32(fliptets, 1, &fc);
17964  // Put the link faces into check list.
17965  for (i = 0; i < 3; i++) {
17966  esym(fliptets[0], newface);
17967  crossfaces->newindex((void **) &parytet);
17968  *parytet = newface;
17969  enextself(fliptets[0]);
17970  }
17971  for (i = 0; i < 3; i++) {
17972  esym(fliptets[1], newface);
17973  crossfaces->newindex((void **) &parytet);
17974  *parytet = newface;
17975  enextself(fliptets[1]);
17976  }
17977  flipflag = 1;
17978  } else if (n == 4) {
17979  if (copcount == 1) {
17980  // Found a 4-to-4 flip.
17981  // Let the six vertices are: a,b,c,d,e,f, where
17982  // fliptets[0] = [b,a,d,c]
17983  // [1] = [b,a,c,e]
17984  // [2] = [b,a,e,f]
17985  // [3] = [b,a,f,d]
17986  // After the 4-to-4 flip, edge [a,b] is flipped, edge [e,d]
17987  // is created.
17988  // First do a 2-to-3 flip.
17989  // Comment: This flip temporarily creates a degenerated
17990  // tet (whose volume is zero). It will be removed by the
17991  // followed 3-to-2 flip.
17992  fliptets[0] = fliptet; // = [a,b,c,d], d is the new vertex.
17993  // fliptets[1]; // = [b,a,c,e].
17994  baktets[0] = fliptets[2]; // = [b,a,e,f]
17995  baktets[1] = fliptets[3]; // = [b,a,f,d]
17996  // The flip may involve hull tets.
17997  flip23(fliptets, 1, &fc);
17998  // Put the "outer" link faces into check list.
17999  // fliptets[0] = [e,d,a,b] => will be flipped, so
18000  // [a,b,d] and [a,b,e] are not "outer" link faces.
18001  for (i = 1; i < 3; i++) {
18002  eprevesym(fliptets[i], newface);
18003  crossfaces->newindex((void **) &parytet);
18004  *parytet = newface;
18005  }
18006  for (i = 1; i < 3; i++) {
18007  enextesym(fliptets[i], newface);
18008  crossfaces->newindex((void **) &parytet);
18009  *parytet = newface;
18010  }
18011  // Then do a 3-to-2 flip.
18012  enextesymself(fliptets[0]); // fliptets[0] is [e,d,a,b].
18013  eprevself(fliptets[0]); // = [b,a,d,c], d is the new vertex.
18014  fliptets[1] = baktets[0]; // = [b,a,e,f]
18015  fliptets[2] = baktets[1]; // = [b,a,f,d]
18016  flip32(fliptets, 1, &fc);
18017  // Put the "outer" link faces into check list.
18018  // fliptets[0] = [d,e,f,a]
18019  // fliptets[1] = [e,d,f,b]
18020  // Faces [a,b,d] and [a,b,e] are not "outer" link faces.
18021  enextself(fliptets[0]);
18022  for (i = 1; i < 3; i++) {
18023  esym(fliptets[0], newface);
18024  crossfaces->newindex((void **) &parytet);
18025  *parytet = newface;
18026  enextself(fliptets[0]);
18027  }
18028  enextself(fliptets[1]);
18029  for (i = 1; i < 3; i++) {
18030  esym(fliptets[1], newface);
18031  crossfaces->newindex((void **) &parytet);
18032  *parytet = newface;
18033  enextself(fliptets[1]);
18034  }
18035  flip23count--;
18036  flip32count--;
18037  flip44count++;
18038  flipflag = 1;
18039  }
18040  }
18041  } else {
18042  // There are more than 1 non-convex or coplanar cases.
18043  flipflag = -1; // Ignore this face.
18044  if (b->verbose > 2) {
18045  printf(" Ignore face (%d, %d, %d) - %d, %d, tau = %.17g\n",
18046  pointmark(bface.forg), pointmark(bface.fdest),
18047  pointmark(bface.fapex), pointmark(bface.foppo),
18048  pointmark(bface.noppo), bface.key);
18049  }
18050  } // if (convcount == 1)
18051 
18052  if (flipflag == 1) {
18053  // Update the priority queue.
18054  for (i = 0; i < crossfaces->objects; i++) {
18055  parytet = (triface *) fastlookup(crossfaces, i);
18056  flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
18057  }
18058  crossfaces->restart();
18059  if (1) { // if (!b->flipinsert_random) {
18060  // Insert all queued unflipped faces.
18061  for (i = 0; i < bfacearray->objects; i++) {
18062  parytet = (triface *) fastlookup(bfacearray, i);
18063  // This face may be changed.
18064  if (!isdeadtet(*parytet)) {
18065  flipcertify(parytet, &pqueue, plane_pa, plane_pb, plane_pc);
18066  }
18067  }
18068  bfacearray->restart();
18069  }
18070  fcount++;
18071  } else if (flipflag == 0) {
18072  // Queue an unflippable face. To process it later.
18073  bfacearray->newindex((void **) &parytet);
18074  *parytet = fliptet;
18075  }
18076  } // if (pe == bface.noppo)
18077  } // if ((pa == bface.forg) && ...)
18078  } // if (bface.tt != NULL)
18079 
18080  } // while (pqueue != NULL)
18081 
18082  if (bfacearray->objects > 0) {
18083  if (fcount == 0) {
18084  printf("!! No flip is found in %ld faces.\n", bfacearray->objects);
18085  terminatetetgen(this, 2); //assert(0);
18086  }
18087  }
18088 
18089  delete bfacearray;
18090 
18091  // Un-mark top and bottom points.
18092  for (i = 0; i < toppoints->objects; i++) {
18093  parypt = (point *) fastlookup(toppoints, i);
18094  punmarktest2(*parypt);
18095  }
18096  for (i = 0; i < botpoints->objects; i++) {
18097  parypt = (point *) fastlookup(botpoints, i);
18098  punmarktest3(*parypt);
18099  }
18100 
18101  f23count = flip23count - f23count;
18102  f32count = flip32count - f32count;
18103  f44count = flip44count - f44count;
18104  totalfcount = f23count + f32count + f44count;
18105  if (b->verbose > 2) {
18106  printf(" Total %ld flips. f23(%ld), f32(%ld), f44(%ld).\n",
18107  totalfcount, f23count, f32count, f44count);
18108  }
18109 }
18110 
18112 // //
18113 // insertpoint_cdt() Insert a new point into a CDT. //
18114 // //
18116 
18117 int tetgenmesh::insertpoint_cdt(point newpt, triface *searchtet, face *splitsh,
18118  face *splitseg, insertvertexflags *ivf,
18119  arraypool *cavpoints, arraypool *cavfaces,
18120  arraypool *cavshells, arraypool *newtets,
18121  arraypool *crosstets, arraypool *misfaces)
18122 {
18123  triface neightet, *parytet;
18124  face checksh, *parysh, *parysh1;
18125  face *paryseg, *paryseg1;
18126  point *parypt;
18127  int t1ver;
18128  int i;
18129 
18130  if (b->verbose > 2) {
18131  printf(" Insert point %d into CDT\n", pointmark(newpt));
18132  }
18133 
18134  if (!insertpoint(newpt, searchtet, NULL, NULL, ivf)) {
18135  // Point is not inserted. Check ivf->iloc for reason.
18136  return 0;
18137  }
18138 
18139 
18140  for (i = 0; i < cavetetvertlist->objects; i++) {
18141  cavpoints->newindex((void **) &parypt);
18142  *parypt = * (point *) fastlookup(cavetetvertlist, i);
18143  }
18144  // Add the new point into the point list.
18145  cavpoints->newindex((void **) &parypt);
18146  *parypt = newpt;
18147 
18148  for (i = 0; i < cavebdrylist->objects; i++) {
18149  cavfaces->newindex((void **) &parytet);
18150  *parytet = * (triface *) fastlookup(cavebdrylist, i);
18151  }
18152 
18153  for (i = 0; i < caveoldtetlist->objects; i++) {
18154  crosstets->newindex((void **) &parytet);
18155  *parytet = * (triface *) fastlookup(caveoldtetlist, i);
18156  }
18157 
18158  cavetetvertlist->restart();
18159  cavebdrylist->restart();
18160  caveoldtetlist->restart();
18161 
18162  // Insert the point using the cavity algorithm.
18163  delaunizecavity(cavpoints, cavfaces, cavshells, newtets, crosstets,
18164  misfaces);
18165  fillcavity(cavshells, NULL, NULL, NULL, NULL, NULL, NULL);
18166  carvecavity(crosstets, newtets, NULL);
18167 
18168  if ((splitsh != NULL) || (splitseg != NULL)) {
18169  // Insert the point into the surface mesh.
18170  sinsertvertex(newpt, splitsh, splitseg, ivf->sloc, ivf->sbowywat, 0);
18171 
18172  // Put all new subfaces into stack.
18173  for (i = 0; i < caveshbdlist->objects; i++) {
18174  // Get an old subface at edge [a, b].
18175  parysh = (face *) fastlookup(caveshbdlist, i);
18176  spivot(*parysh, checksh); // The new subface [a, b, p].
18177  // Do not recover a deleted new face (degenerated).
18178  if (checksh.sh[3] != NULL) {
18179  subfacstack->newindex((void **) &parysh);
18180  *parysh = checksh;
18181  }
18182  }
18183 
18184  if (splitseg != NULL) {
18185  // Queue two new subsegments in C(p) for recovery.
18186  for (i = 0; i < cavesegshlist->objects; i++) {
18187  paryseg = (face *) fastlookup(cavesegshlist, i);
18188  subsegstack->newindex((void **) &paryseg1);
18189  *paryseg1 = *paryseg;
18190  }
18191  } // if (splitseg != NULL)
18192 
18193  // Delete the old subfaces in sC(p).
18194  for (i = 0; i < caveshlist->objects; i++) {
18195  parysh = (face *) fastlookup(caveshlist, i);
18196  if (checksubfaceflag) {
18197  // It is possible that this subface still connects to adjacent
18198  // tets which are not in C(p). If so, clear connections in the
18199  // adjacent tets at this subface.
18200  stpivot(*parysh, neightet);
18201  if (neightet.tet != NULL) {
18202  if (neightet.tet[4] != NULL) {
18203  // Found an adjacent tet. It must be not in C(p).
18204  tsdissolve(neightet);
18205  fsymself(neightet);
18206  tsdissolve(neightet);
18207  }
18208  }
18209  }
18210  shellfacedealloc(subfaces, parysh->sh);
18211  }
18212  if (splitseg != NULL) {
18213  // Delete the old segment in sC(p).
18214  shellfacedealloc(subsegs, splitseg->sh);
18215  }
18216 
18217  // Clear working lists.
18218  caveshlist->restart();
18219  caveshbdlist->restart();
18220  cavesegshlist->restart();
18221  } // if ((splitsh != NULL) || (splitseg != NULL))
18222 
18223  // Put all interior subfaces into stack for recovery.
18224  // They were collected in carvecavity().
18225  // Note: Some collected subfaces may be deleted by sinsertvertex().
18226  for (i = 0; i < caveencshlist->objects; i++) {
18227  parysh = (face *) fastlookup(caveencshlist, i);
18228  if (parysh->sh[3] != NULL) {
18229  subfacstack->newindex((void **) &parysh1);
18230  *parysh1 = *parysh;
18231  }
18232  }
18233 
18234  // Put all interior segments into stack for recovery.
18235  // They were collected in carvecavity().
18236  // Note: Some collected segments may be deleted by sinsertvertex().
18237  for (i = 0; i < caveencseglist->objects; i++) {
18238  paryseg = (face *) fastlookup(caveencseglist, i);
18239  if (paryseg->sh[3] != NULL) {
18240  subsegstack->newindex((void **) &paryseg1);
18241  *paryseg1 = *paryseg;
18242  }
18243  }
18244 
18245  caveencshlist->restart();
18246  caveencseglist->restart();
18247 
18248  return 1;
18249 }
18250 
18252 // //
18253 // refineregion() Refine a missing region by inserting points. //
18254 // //
18255 // 'splitsh' represents an edge of the facet to be split. It must be not a //
18256 // segment.
18257 // //
18258 // Assumption: The current mesh is a CDT and is convex. //
18259 // //
18261 
18262 void tetgenmesh::refineregion(face &splitsh, arraypool *cavpoints,
18263  arraypool *cavfaces, arraypool *cavshells,
18264  arraypool *newtets, arraypool *crosstets,
18265  arraypool *misfaces)
18266 {
18267  triface searchtet, spintet;
18268  face splitseg, *paryseg;
18269  point steinpt, pa, pb, refpt;
18270  insertvertexflags ivf;
18271  enum interresult dir;
18272  long baknum = points->items;
18273  int t1ver;
18274  int i;
18275 
18276  // Do not split a segment.
18277  for (i = 0; i < 3; i++) {
18278  sspivot(splitsh, splitseg);
18279  if (splitseg.sh == NULL) break;
18280  senextself(splitsh);
18281  }
18282 
18283  if (b->verbose > 2) {
18284  printf(" Refining region at edge (%d, %d, %d).\n",
18285  pointmark(sorg(splitsh)), pointmark(sdest(splitsh)),
18286  pointmark(sapex(splitsh)));
18287  }
18288 
18289  // Add the Steiner point at the barycenter of the face.
18290  pa = sorg(splitsh);
18291  pb = sdest(splitsh);
18292  // Create a new point.
18293  makepoint(&steinpt, FREEFACETVERTEX);
18294  for (i = 0; i < 3; i++) {
18295  steinpt[i] = 0.5 * (pa[i] + pb[i]);
18296  }
18297 
18298  ivf.bowywat = 1; // Use the Bowyer-Watson algorrithm.
18299  ivf.cdtflag = 1; // Only create the initial cavity.
18300  ivf.sloc = (int) ONEDGE;
18301  ivf.sbowywat = 1;
18302  ivf.assignmeshsize = b->metric;
18303  ivf.smlenflag = useinsertradius; // Return the closet mesh vertex.
18304 
18305  point2tetorg(pa, searchtet); // Start location from it.
18306  ivf.iloc = (int) OUTSIDE;
18307 
18308  ivf.rejflag = 1; // Reject it if it encroaches upon any segment.
18309  if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, NULL, &ivf, cavpoints,
18310  cavfaces, cavshells, newtets, crosstets, misfaces)) {
18311  if (ivf.iloc == (int) ENCSEGMENT) {
18312  pointdealloc(steinpt);
18313  // Split an encroached segment.
18314  i = randomnation(encseglist->objects);
18315  paryseg = (face *) fastlookup(encseglist, i);
18316  splitseg = *paryseg;
18317  encseglist->restart();
18318 
18319  // Split the segment.
18320  pa = sorg(splitseg);
18321  pb = sdest(splitseg);
18322  // Create a new point.
18323  makepoint(&steinpt, FREESEGVERTEX);
18324  for (i = 0; i < 3; i++) {
18325  steinpt[i] = 0.5 * (pa[i] + pb[i]);
18326  }
18327  point2tetorg(pa, searchtet);
18328  ivf.iloc = (int) OUTSIDE;
18329  ivf.rejflag = 0;
18330  if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, &splitseg, &ivf,
18331  cavpoints, cavfaces, cavshells, newtets,
18332  crosstets, misfaces)) {
18333  terminatetetgen(this, 2);
18334  }
18335  if (useinsertradius) {
18336  save_segmentpoint_insradius(steinpt, ivf.parentpt, ivf.smlen);
18337  }
18338  st_segref_count++;
18339  if (steinerleft > 0) steinerleft--;
18340  } else {
18341  terminatetetgen(this, 2); // assert(0);
18342  }
18343  } else {
18344  if (useinsertradius) {
18345  save_facetpoint_insradius(steinpt, ivf.parentpt, ivf.smlen);
18346  }
18347  st_facref_count++;
18348  if (steinerleft > 0) steinerleft--;
18349  }
18350 
18351  while (subsegstack->objects > 0l) {
18352  // seglist is used as a stack.
18353  subsegstack->objects--;
18354  paryseg = (face *) fastlookup(subsegstack, subsegstack->objects);
18355  splitseg = *paryseg;
18356 
18357  // Check if this segment has been recovered.
18358  sstpivot1(splitseg, searchtet);
18359  if (searchtet.tet != NULL) continue;
18360 
18361  // Search the segment.
18362  dir = scoutsegment(sorg(splitseg), sdest(splitseg), &splitseg, &searchtet,
18363  &refpt, NULL);
18364  if (dir == SHAREEDGE) {
18365  // Found this segment, insert it.
18366  // Let the segment remember an adjacent tet.
18367  sstbond1(splitseg, searchtet);
18368  // Bond the segment to all tets containing it.
18369  spintet = searchtet;
18370  do {
18371  tssbond1(spintet, splitseg);
18372  fnextself(spintet);
18373  } while (spintet.tet != searchtet.tet);
18374  } else {
18375  if ((dir == ACROSSFACE) || (dir == ACROSSEDGE)) {
18376  // Split the segment.
18377  makepoint(&steinpt, FREESEGVERTEX);
18378  getsteinerptonsegment(&splitseg, refpt, steinpt);
18379  ivf.iloc = (int) OUTSIDE;
18380  ivf.rejflag = 0;
18381  if (!insertpoint_cdt(steinpt, &searchtet, &splitsh, &splitseg, &ivf,
18382  cavpoints, cavfaces, cavshells, newtets,
18383  crosstets, misfaces)) {
18384  terminatetetgen(this, 2);
18385  }
18386  if (useinsertradius) {
18387  save_segmentpoint_insradius(steinpt, ivf.parentpt, ivf.smlen);
18388  }
18389  st_segref_count++;
18390  if (steinerleft > 0) steinerleft--;
18391  } else {
18392  terminatetetgen(this, 2);
18393  }
18394  }
18395  } // while
18396 
18397  if (b->verbose > 2) {
18398  printf(" Added %ld Steiner points.\n", points->items - baknum);
18399  }
18400 }
18401 
18403 // //
18404 // constrainedfacets() Recover constrained facets in a CDT. //
18405 // //
18406 // All unrecovered subfaces are queued in 'subfacestack'. //
18407 // //
18409 
18410 void tetgenmesh::constrainedfacets()
18411 {
18412  arraypool *tg_crosstets, *tg_topnewtets, *tg_botnewtets;
18413  arraypool *tg_topfaces, *tg_botfaces, *tg_midfaces;
18414  arraypool *tg_topshells, *tg_botshells, *tg_facfaces;
18415  arraypool *tg_toppoints, *tg_botpoints;
18416  arraypool *tg_missingshs, *tg_missingshbds, *tg_missingshverts;
18417  triface searchtet, neightet, crossedge;
18418  face searchsh, *parysh, *parysh1;
18419  face *paryseg;
18420  point *parypt;
18421  enum interresult dir;
18422  int facetcount;
18423  int success;
18424  int t1ver;
18425  int i, j;
18426 
18427  // Initialize arrays.
18428  tg_crosstets = new arraypool(sizeof(triface), 10);
18429  tg_topnewtets = new arraypool(sizeof(triface), 10);
18430  tg_botnewtets = new arraypool(sizeof(triface), 10);
18431  tg_topfaces = new arraypool(sizeof(triface), 10);
18432  tg_botfaces = new arraypool(sizeof(triface), 10);
18433  tg_midfaces = new arraypool(sizeof(triface), 10);
18434  tg_toppoints = new arraypool(sizeof(point), 8);
18435  tg_botpoints = new arraypool(sizeof(point), 8);
18436  tg_facfaces = new arraypool(sizeof(face), 10);
18437  tg_topshells = new arraypool(sizeof(face), 10);
18438  tg_botshells = new arraypool(sizeof(face), 10);
18439  tg_missingshs = new arraypool(sizeof(face), 10);
18440  tg_missingshbds = new arraypool(sizeof(face), 10);
18441  tg_missingshverts = new arraypool(sizeof(point), 8);
18442  // This is a global array used by refineregion().
18443  encseglist = new arraypool(sizeof(face), 4);
18444 
18445  facetcount = 0;
18446 
18447  while (subfacstack->objects > 0l) {
18448 
18449  subfacstack->objects--;
18450  parysh = (face *) fastlookup(subfacstack, subfacstack->objects);
18451  searchsh = *parysh;
18452 
18453  if (searchsh.sh[3] == NULL) continue; // It is dead.
18454  if (isshtet(searchsh)) continue; // It is recovered.
18455 
18456  // Collect all unrecovered subfaces which are co-facet.
18457  smarktest(searchsh);
18458  tg_facfaces->newindex((void **) &parysh);
18459  *parysh = searchsh;
18460  for (i = 0; i < tg_facfaces->objects; i++) {
18461  parysh = (face *) fastlookup(tg_facfaces, i);
18462  for (j = 0; j < 3; j++) {
18463  if (!isshsubseg(*parysh)) {
18464  spivot(*parysh, searchsh);
18465  if (!smarktested(searchsh)) {
18466  if (!isshtet(searchsh)) {
18467  smarktest(searchsh);
18468  tg_facfaces->newindex((void **) &parysh1);
18469  *parysh1 = searchsh;
18470  }
18471  }
18472  }
18473  senextself(*parysh);
18474  } // j
18475  } // i
18476  // Have found all facet subfaces. Unmark them.
18477  for (i = 0; i < tg_facfaces->objects; i++) {
18478  parysh = (face *) fastlookup(tg_facfaces, i);
18479  sunmarktest(*parysh);
18480  }
18481 
18482  if (b->verbose > 1) {
18483  printf(" Recovering facet #%d: %ld subfaces.\n", facetcount + 1,
18484  tg_facfaces->objects);
18485  }
18486  facetcount++;
18487 
18488  while (tg_facfaces->objects > 0l) {
18489 
18490  tg_facfaces->objects--;
18491  parysh = (face *) fastlookup(tg_facfaces, tg_facfaces->objects);
18492  searchsh = *parysh;
18493 
18494  if (searchsh.sh[3] == NULL) continue; // It is dead.
18495  if (isshtet(searchsh)) continue; // It is recovered.
18496 
18497  searchtet.tet = NULL;
18498  if (scoutsubface(&searchsh, &searchtet, 1)) continue;
18499 
18500  // The subface is missing. Form the missing region.
18501  // Re-use 'tg_crosstets' for 'adjtets'.
18502  formregion(&searchsh, tg_missingshs, tg_missingshbds, tg_missingshverts);
18503 
18504  int searchflag = scoutcrossedge(searchtet, tg_missingshbds, tg_missingshs);
18505  if (searchflag > 0) {
18506  // Save this crossing edge, will be used by fillcavity().
18507  crossedge = searchtet;
18508  // Form a cavity of crossing tets.
18509  success = formcavity(&searchtet, tg_missingshs, tg_crosstets,
18510  tg_topfaces, tg_botfaces, tg_toppoints,
18511  tg_botpoints);
18512  if (success) {
18513  if (!b->flipinsert) {
18514  // Tetrahedralize the top part. Re-use 'tg_midfaces'.
18515  delaunizecavity(tg_toppoints, tg_topfaces, tg_topshells,
18516  tg_topnewtets, tg_crosstets, tg_midfaces);
18517  // Tetrahedralize the bottom part. Re-use 'tg_midfaces'.
18518  delaunizecavity(tg_botpoints, tg_botfaces, tg_botshells,
18519  tg_botnewtets, tg_crosstets, tg_midfaces);
18520  // Fill the cavity with new tets.
18521  success = fillcavity(tg_topshells, tg_botshells, tg_midfaces,
18522  tg_missingshs, tg_topnewtets, tg_botnewtets,
18523  &crossedge);
18524  if (success) {
18525  // Cavity is remeshed. Delete old tets and outer new tets.
18526  carvecavity(tg_crosstets, tg_topnewtets, tg_botnewtets);
18527  } else {
18528  restorecavity(tg_crosstets, tg_topnewtets, tg_botnewtets,
18529  tg_missingshbds);
18530  }
18531  } else {
18532  // Use the flip algorithm of Shewchuk to recover the subfaces.
18533  flipinsertfacet(tg_crosstets, tg_toppoints, tg_botpoints,
18534  tg_missingshverts);
18535  // Put all subfaces in R back to tg_facfaces.
18536  for (i = 0; i < tg_missingshs->objects; i++) {
18537  parysh = (face *) fastlookup(tg_missingshs, i);
18538  tg_facfaces->newindex((void **) &parysh1);
18539  *parysh1 = *parysh;
18540  }
18541  success = 1;
18542  // Clear working lists.
18543  tg_crosstets->restart();
18544  tg_topfaces->restart();
18545  tg_botfaces->restart();
18546  tg_toppoints->restart();
18547  tg_botpoints->restart();
18548  } // b->flipinsert
18549 
18550  if (success) {
18551  // Recover interior subfaces.
18552  for (i = 0; i < caveencshlist->objects; i++) {
18553  parysh = (face *) fastlookup(caveencshlist, i);
18554  if (!scoutsubface(parysh, &searchtet, 1)) {
18555  // Add this face at the end of the list, so it will be
18556  // processed immediately.
18557  tg_facfaces->newindex((void **) &parysh1);
18558  *parysh1 = *parysh;
18559  }
18560  }
18561  caveencshlist->restart();
18562  // Recover interior segments. This should always be recovered.
18563  for (i = 0; i < caveencseglist->objects; i++) {
18564  paryseg = (face *) fastlookup(caveencseglist, i);
18565  dir = scoutsegment(sorg(*paryseg), sdest(*paryseg), paryseg,
18566  &searchtet, NULL, NULL);
18567  if (dir != SHAREEDGE) {
18568  terminatetetgen(this, 2);
18569  }
18570  // Insert this segment.
18571  // Let the segment remember an adjacent tet.
18572  sstbond1(*paryseg, searchtet);
18573  // Bond the segment to all tets containing it.
18574  neightet = searchtet;
18575  do {
18576  tssbond1(neightet, *paryseg);
18577  fnextself(neightet);
18578  } while (neightet.tet != searchtet.tet);
18579  }
18580  caveencseglist->restart();
18581  } // success - remesh cavity
18582  } // success - form cavity
18583  else {
18584  terminatetetgen(this, 2); // Report a bug.
18585  } // Not success - form cavity
18586  } else {
18587  // Put all subfaces in R back to tg_facfaces.
18588  for (i = 0; i < tg_missingshs->objects; i++) {
18589  parysh = (face *) fastlookup(tg_missingshs, i);
18590  tg_facfaces->newindex((void **) &parysh1);
18591  *parysh1 = *parysh;
18592  }
18593  if (searchflag != -1) {
18594  // Some edge(s) in the missing regions were flipped.
18595  success = 1;
18596  } else {
18597  restorecavity(tg_crosstets, tg_topnewtets, tg_botnewtets,
18598  tg_missingshbds); // Only remove fake segments.
18599  // Choose an edge to split (set in recentsh)
18600  recentsh = searchsh;
18601  success = 0; // Do refineregion();
18602  }
18603  } // if (scoutcrossedge)
18604 
18605  // Unmarktest all points of the missing region.
18606  for (i = 0; i < tg_missingshverts->objects; i++) {
18607  parypt = (point *) fastlookup(tg_missingshverts, i);
18608  punmarktest(*parypt);
18609  }
18610  tg_missingshverts->restart();
18611  tg_missingshbds->restart();
18612  tg_missingshs->restart();
18613 
18614  if (!success) {
18615  // The missing region can not be recovered. Refine it.
18616  refineregion(recentsh, tg_toppoints, tg_topfaces, tg_topshells,
18617  tg_topnewtets, tg_crosstets, tg_midfaces);
18618  }
18619  } // while (tg_facfaces->objects)
18620 
18621  } // while ((subfacstack->objects)
18622 
18623  // Accumulate the dynamic memory.
18624  totalworkmemory += (tg_crosstets->totalmemory + tg_topnewtets->totalmemory +
18625  tg_botnewtets->totalmemory + tg_topfaces->totalmemory +
18626  tg_botfaces->totalmemory + tg_midfaces->totalmemory +
18627  tg_toppoints->totalmemory + tg_botpoints->totalmemory +
18628  tg_facfaces->totalmemory + tg_topshells->totalmemory +
18629  tg_botshells->totalmemory + tg_missingshs->totalmemory +
18630  tg_missingshbds->totalmemory +
18631  tg_missingshverts->totalmemory +
18632  encseglist->totalmemory);
18633 
18634  // Delete arrays.
18635  delete tg_crosstets;
18636  delete tg_topnewtets;
18637  delete tg_botnewtets;
18638  delete tg_topfaces;
18639  delete tg_botfaces;
18640  delete tg_midfaces;
18641  delete tg_toppoints;
18642  delete tg_botpoints;
18643  delete tg_facfaces;
18644  delete tg_topshells;
18645  delete tg_botshells;
18646  delete tg_missingshs;
18647  delete tg_missingshbds;
18648  delete tg_missingshverts;
18649  delete encseglist;
18650  encseglist = NULL;
18651 }
18652 
18654 // //
18655 // constraineddelaunay() Create a constrained Delaunay tetrahedralization.//
18656 // //
18658 
18659 void tetgenmesh::constraineddelaunay(clock_t& tv)
18660 {
18661  face searchsh, *parysh;
18662  face searchseg, *paryseg;
18663  int s, i;
18664 
18665  // Statistics.
18666  long bakfillregioncount;
18667  long bakcavitycount, bakcavityexpcount;
18668  long bakseg_ref_count;
18669 
18670  if (!b->quiet) {
18671  printf("Constrained Delaunay...\n");
18672  }
18673 
18674  makesegmentendpointsmap();
18675  makefacetverticesmap();
18676 
18677  if (b->verbose) {
18678  printf(" Delaunizing segments.\n");
18679  }
18680 
18681  checksubsegflag = 1;
18682 
18683  // Put all segments into the list (in random order).
18684  subsegs->traversalinit();
18685  for (i = 0; i < subsegs->items; i++) {
18686  s = randomnation(i + 1);
18687  // Move the s-th seg to the i-th.
18688  subsegstack->newindex((void **) &paryseg);
18689  *paryseg = * (face *) fastlookup(subsegstack, s);
18690  // Put i-th seg to be the s-th.
18691  searchseg.sh = shellfacetraverse(subsegs);
18692  //sinfect(searchseg); // Only save it once.
18693  paryseg = (face *) fastlookup(subsegstack, s);
18694  *paryseg = searchseg;
18695  }
18696 
18697  // Recover non-Delaunay segments.
18698  delaunizesegments();
18699 
18700  if (b->verbose) {
18701  printf(" Inserted %ld Steiner points.\n", st_segref_count);
18702  }
18703 
18704  tv = clock();
18705 
18706  if (b->verbose) {
18707  printf(" Constraining facets.\n");
18708  }
18709 
18710  // Subfaces will be introduced.
18711  checksubfaceflag = 1;
18712 
18713  bakfillregioncount = fillregioncount;
18714  bakcavitycount = cavitycount;
18715  bakcavityexpcount = cavityexpcount;
18716  bakseg_ref_count = st_segref_count;
18717 
18718  // Randomly order the subfaces.
18719  subfaces->traversalinit();
18720  for (i = 0; i < subfaces->items; i++) {
18721  s = randomnation(i + 1);
18722  // Move the s-th subface to the i-th.
18723  subfacstack->newindex((void **) &parysh);
18724  *parysh = * (face *) fastlookup(subfacstack, s);
18725  // Put i-th subface to be the s-th.
18726  searchsh.sh = shellfacetraverse(subfaces);
18727  parysh = (face *) fastlookup(subfacstack, s);
18728  *parysh = searchsh;
18729  }
18730 
18731  // Recover facets.
18732  constrainedfacets();
18733 
18734  if (b->verbose) {
18735  if (fillregioncount > bakfillregioncount) {
18736  printf(" Remeshed %ld regions.\n", fillregioncount-bakfillregioncount);
18737  }
18738  if (cavitycount > bakcavitycount) {
18739  printf(" Remeshed %ld cavities", cavitycount - bakcavitycount);
18740  if (cavityexpcount - bakcavityexpcount) {
18741  printf(" (%ld enlarged)", cavityexpcount - bakcavityexpcount);
18742  }
18743  printf(".\n");
18744  }
18745  if (st_segref_count + st_facref_count - bakseg_ref_count > 0) {
18746  printf(" Inserted %ld (%ld, %ld) refine points.\n",
18747  st_segref_count + st_facref_count - bakseg_ref_count,
18748  st_segref_count - bakseg_ref_count, st_facref_count);
18749  }
18750  }
18751 }
18752 
18756 
18760 
18762 // //
18763 // checkflipeligibility() A call back function for boundary recovery. //
18764 // //
18765 // 'fliptype' indicates which elementary flip will be performed: 1 : 2-to-3, //
18766 // and 2 : 3-to-2, respectively. //
18767 // //
18768 // 'pa, ..., pe' are the vertices involved in this flip, where [a,b,c] is //
18769 // the flip face, and [d,e] is the flip edge. NOTE: 'pc' may be 'dummypoint',//
18770 // other points must not be 'dummypoint'. //
18771 // //
18773 
18774 int tetgenmesh::checkflipeligibility(int fliptype, point pa, point pb,
18775  point pc, point pd, point pe,
18776  int level, int edgepivot,
18777  flipconstraints* fc)
18778 {
18779  point tmppts[3];
18780  enum interresult dir;
18781  int types[2], poss[4];
18782  int intflag;
18783  int rejflag = 0;
18784  int i;
18785 
18786  if (fc->seg[0] != NULL) {
18787  // A constraining edge is given (e.g., for edge recovery).
18788  if (fliptype == 1) {
18789  // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c].
18790  tmppts[0] = pa;
18791  tmppts[1] = pb;
18792  tmppts[2] = pc;
18793  for (i = 0; i < 3 && !rejflag; i++) {
18794  if (tmppts[i] != dummypoint) {
18795  // Test if the face [e,d,#] intersects the edge.
18796  intflag = tri_edge_test(pe, pd, tmppts[i], fc->seg[0], fc->seg[1],
18797  NULL, 1, types, poss);
18798  if (intflag == 2) {
18799  // They intersect at a single point.
18800  dir = (enum interresult) types[0];
18801  if (dir == ACROSSFACE) {
18802  // The interior of [e,d,#] intersect the segment.
18803  rejflag = 1;
18804  } else if (dir == ACROSSEDGE) {
18805  if (poss[0] == 0) {
18806  // The interior of [e,d] intersect the segment.
18807  // Since [e,d] is the newly created edge. Reject this flip.
18808  rejflag = 1;
18809  }
18810  }
18811  } else if (intflag == 4) {
18812  // They may intersect at either a point or a line segment.
18813  dir = (enum interresult) types[0];
18814  if (dir == ACROSSEDGE) {
18815  if (poss[0] == 0) {
18816  // The interior of [e,d] intersect the segment.
18817  // Since [e,d] is the newly created edge. Reject this flip.
18818  rejflag = 1;
18819  }
18820  }
18821  }
18822  } // if (tmppts[0] != dummypoint)
18823  } // i
18824  } else if (fliptype == 2) {
18825  // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c]
18826  if (pc != dummypoint) {
18827  // Check if the new face [a,b,c] intersect the edge in its interior.
18828  intflag = tri_edge_test(pa, pb, pc, fc->seg[0], fc->seg[1], NULL,
18829  1, types, poss);
18830  if (intflag == 2) {
18831  // They intersect at a single point.
18832  dir = (enum interresult) types[0];
18833  if (dir == ACROSSFACE) {
18834  // The interior of [a,b,c] intersect the segment.
18835  rejflag = 1; // Do not flip.
18836  }
18837  } else if (intflag == 4) {
18838  // [a,b,c] is coplanar with the edge.
18839  dir = (enum interresult) types[0];
18840  if (dir == ACROSSEDGE) {
18841  // The boundary of [a,b,c] intersect the segment.
18842  rejflag = 1; // Do not flip.
18843  }
18844  }
18845  } // if (pc != dummypoint)
18846  }
18847  } // if (fc->seg[0] != NULL)
18848 
18849  if ((fc->fac[0] != NULL) && !rejflag) {
18850  // A constraining face is given (e.g., for face recovery).
18851  if (fliptype == 1) {
18852  // A 2-to-3 flip.
18853  // Test if the new edge [e,d] intersects the face.
18854  intflag = tri_edge_test(fc->fac[0], fc->fac[1], fc->fac[2], pe, pd,
18855  NULL, 1, types, poss);
18856  if (intflag == 2) {
18857  // They intersect at a single point.
18858  dir = (enum interresult) types[0];
18859  if (dir == ACROSSFACE) {
18860  rejflag = 1;
18861  } else if (dir == ACROSSEDGE) {
18862  rejflag = 1;
18863  }
18864  } else if (intflag == 4) {
18865  // The edge [e,d] is coplanar with the face.
18866  // There may be two intersections.
18867  for (i = 0; i < 2 && !rejflag; i++) {
18868  dir = (enum interresult) types[i];
18869  if (dir == ACROSSFACE) {
18870  rejflag = 1;
18871  } else if (dir == ACROSSEDGE) {
18872  rejflag = 1;
18873  }
18874  }
18875  }
18876  } // if (fliptype == 1)
18877  } // if (fc->fac[0] != NULL)
18878 
18879  if ((fc->remvert != NULL) && !rejflag) {
18880  // The vertex is going to be removed. Do not create a new edge which
18881  // contains this vertex.
18882  if (fliptype == 1) {
18883  // A 2-to-3 flip.
18884  if ((pd == fc->remvert) || (pe == fc->remvert)) {
18885  rejflag = 1;
18886  }
18887  }
18888  }
18889 
18890  if (fc->remove_large_angle && !rejflag) {
18891  // Remove a large dihedral angle. Do not create a new small angle.
18892  REAL cosmaxd = 0, diff;
18893  if (fliptype == 1) {
18894  // We assume that neither 'a' nor 'b' is dummypoint.
18895  // A 2-to-3 flip: [a,b,c] => [e,d,a], [e,d,b], [e,d,c].
18896  // The new tet [e,d,a,b] will be flipped later. Only two new tets:
18897  // [e,d,b,c] and [e,d,c,a] need to be checked.
18898  if ((pc != dummypoint) && (pe != dummypoint) && (pd != dummypoint)) {
18899  // Get the largest dihedral angle of [e,d,b,c].
18900  tetalldihedral(pe, pd, pb, pc, NULL, &cosmaxd, NULL);
18901  diff = cosmaxd - fc->cosdihed_in;
18902  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding.
18903  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18904  rejflag = 1;
18905  } else {
18906  // Record the largest new angle.
18907  if (cosmaxd < fc->cosdihed_out) {
18908  fc->cosdihed_out = cosmaxd;
18909  }
18910  // Get the largest dihedral angle of [e,d,c,a].
18911  tetalldihedral(pe, pd, pc, pa, NULL, &cosmaxd, NULL);
18912  diff = cosmaxd - fc->cosdihed_in;
18913  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding.
18914  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18915  rejflag = 1;
18916  } else {
18917  // Record the largest new angle.
18918  if (cosmaxd < fc->cosdihed_out) {
18919  fc->cosdihed_out = cosmaxd;
18920  }
18921  }
18922  }
18923  } // if (pc != dummypoint && ...)
18924  } else if (fliptype == 2) {
18925  // A 3-to-2 flip: [e,d,a], [e,d,b], [e,d,c] => [a,b,c]
18926  // We assume that neither 'e' nor 'd' is dummypoint.
18927  if (level == 0) {
18928  // Both new tets [a,b,c,d] and [b,a,c,e] are new tets.
18929  if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
18930  // Get the largest dihedral angle of [a,b,c,d].
18931  tetalldihedral(pa, pb, pc, pd, NULL, &cosmaxd, NULL);
18932  diff = cosmaxd - fc->cosdihed_in;
18933  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0; // Rounding
18934  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18935  rejflag = 1;
18936  } else {
18937  // Record the largest new angle.
18938  if (cosmaxd < fc->cosdihed_out) {
18939  fc->cosdihed_out = cosmaxd;
18940  }
18941  // Get the largest dihedral angle of [b,a,c,e].
18942  tetalldihedral(pb, pa, pc, pe, NULL, &cosmaxd, NULL);
18943  diff = cosmaxd - fc->cosdihed_in;
18944  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
18945  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18946  rejflag = 1;
18947  } else {
18948  // Record the largest new angle.
18949  if (cosmaxd < fc->cosdihed_out) {
18950  fc->cosdihed_out = cosmaxd;
18951  }
18952  }
18953  }
18954  }
18955  } else { // level > 0
18956  if (edgepivot == 1) {
18957  // The new tet [a,b,c,d] will be flipped. Only check [b,a,c,e].
18958  if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
18959  // Get the largest dihedral angle of [b,a,c,e].
18960  tetalldihedral(pb, pa, pc, pe, NULL, &cosmaxd, NULL);
18961  diff = cosmaxd - fc->cosdihed_in;
18962  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
18963  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18964  rejflag = 1;
18965  } else {
18966  // Record the largest new angle.
18967  if (cosmaxd < fc->cosdihed_out) {
18968  fc->cosdihed_out = cosmaxd;
18969  }
18970  }
18971  }
18972  } else {
18973  // The new tet [b,a,c,e] will be flipped. Only check [a,b,c,d].
18974  if ((pa != dummypoint) && (pb != dummypoint) && (pc != dummypoint)) {
18975  // Get the largest dihedral angle of [b,a,c,e].
18976  tetalldihedral(pa, pb, pc, pd, NULL, &cosmaxd, NULL);
18977  diff = cosmaxd - fc->cosdihed_in;
18978  if (fabs(diff/fc->cosdihed_in) < b->epsilon) diff = 0.0;// Rounding
18979  if (diff <= 0) { //if (cosmaxd <= fc->cosdihed_in) {
18980  rejflag = 1;
18981  } else {
18982  // Record the largest new angle.
18983  if (cosmaxd < fc->cosdihed_out) {
18984  fc->cosdihed_out = cosmaxd;
18985  }
18986  }
18987  }
18988  } // edgepivot
18989  } // level
18990  }
18991  }
18992 
18993  return rejflag;
18994 }
18995 
18997 // //
18998 // removeedgebyflips() Attempt to remove an edge by flips. //
18999 // //
19000 // 'flipedge' is a non-convex or flat edge [a,b,#,#] to be removed. //
19001 // //
19002 // The return value is a positive integer, it indicates whether the edge is //
19003 // removed or not. A value "2" means the edge is removed, otherwise, the //
19004 // edge is not removed and the value (must >= 3) is the current number of //
19005 // tets in the edge star. //
19006 // //
19008 
19009 int tetgenmesh::removeedgebyflips(triface *flipedge, flipconstraints* fc)
19010 {
19011  triface *abtets, spintet;
19012  int t1ver;
19013  int n, nn, i;
19014 
19015 
19016  if (checksubsegflag) {
19017  // Do not flip a segment.
19018  if (issubseg(*flipedge)) {
19019  if (fc->collectencsegflag) {
19020  face checkseg, *paryseg;
19021  tsspivot1(*flipedge, checkseg);
19022  if (!sinfected(checkseg)) {
19023  // Queue this segment in list.
19024  sinfect(checkseg);
19025  caveencseglist->newindex((void **) &paryseg);
19026  *paryseg = checkseg;
19027  }
19028  }
19029  return 0;
19030  }
19031  }
19032 
19033  // Count the number of tets at edge [a,b].
19034  n = 0;
19035  spintet = *flipedge;
19036  while (1) {
19037  n++;
19038  fnextself(spintet);
19039  if (spintet.tet == flipedge->tet) break;
19040  }
19041  if (n < 3) {
19042  // It is only possible when the mesh contains inverted tetrahedra.
19043  terminatetetgen(this, 2); // Report a bug
19044  }
19045 
19046  if ((b->flipstarsize > 0) && (n > b->flipstarsize)) {
19047  // The star size exceeds the limit.
19048  return 0; // Do not flip it.
19049  }
19050 
19051  // Allocate spaces.
19052  abtets = new triface[n];
19053  // Collect the tets at edge [a,b].
19054  spintet = *flipedge;
19055  i = 0;
19056  while (1) {
19057  abtets[i] = spintet;
19058  setelemcounter(abtets[i], 1);
19059  i++;
19060  fnextself(spintet);
19061  if (spintet.tet == flipedge->tet) break;
19062  }
19063 
19064 
19065  // Try to flip the edge (level = 0, edgepivot = 0).
19066  nn = flipnm(abtets, n, 0, 0, fc);
19067 
19068 
19069  if (nn > 2) {
19070  // Edge is not flipped. Unmarktest the remaining tets in Star(ab).
19071  for (i = 0; i < nn; i++) {
19072  setelemcounter(abtets[i], 0);
19073  }
19074  // Restore the input edge (needed by Lawson's flip).
19075  *flipedge = abtets[0];
19076  }
19077 
19078  // Release the temporary allocated spaces.
19079  // NOTE: fc->unflip must be 0.
19080  int bakunflip = fc->unflip;
19081  fc->unflip = 0;
19082  flipnm_post(abtets, n, nn, 0, fc);
19083  fc->unflip = bakunflip;
19084 
19085  delete [] abtets;
19086 
19087  return nn;
19088 }
19089 
19091 // //
19092 // removefacebyflips() Remove a face by flips. //
19093 // //
19094 // Return 1 if the face is removed. Otherwise, return 0. //
19095 // //
19096 // ASSUMPTIONS: //
19097 // - 'flipface' must not be a subface. //
19098 // - 'flipface' must not be a hull face. //
19099 // //
19101 
19102 int tetgenmesh::removefacebyflips(triface *flipface, flipconstraints* fc)
19103 {
19104  triface fliptets[3], flipedge;
19105  point pa, pb, pc, pd, pe;
19106  REAL ori;
19107  int reducflag = 0;
19108 
19109  fliptets[0] = *flipface;
19110  fsym(*flipface, fliptets[1]);
19111  pa = org(fliptets[0]);
19112  pb = dest(fliptets[0]);
19113  pc = apex(fliptets[0]);
19114  pd = oppo(fliptets[0]);
19115  pe = oppo(fliptets[1]);
19116 
19117  ori = orient3d(pa, pb, pd, pe);
19118  if (ori > 0) {
19119  ori = orient3d(pb, pc, pd, pe);
19120  if (ori > 0) {
19121  ori = orient3d(pc, pa, pd, pe);
19122  if (ori > 0) {
19123  // Found a 2-to-3 flip.
19124  reducflag = 1;
19125  } else {
19126  eprev(*flipface, flipedge); // [c,a]
19127  }
19128  } else {
19129  enext(*flipface, flipedge); // [b,c]
19130  }
19131  } else {
19132  flipedge = *flipface; // [a,b]
19133  }
19134 
19135  if (reducflag) {
19136  // A 2-to-3 flip is found.
19137  flip23(fliptets, 0, fc);
19138  return 1;
19139  } else {
19140  // Try to flip the selected edge of this face.
19141  if (removeedgebyflips(&flipedge, fc) == 2) {
19142  return 1;
19143  }
19144  }
19145 
19146  // Face is not removed.
19147  return 0;
19148 }
19149 
19151 // //
19152 // recoveredge() Recover an edge in current tetrahedralization. //
19153 // //
19154 // If the edge is recovered, 'searchtet' returns a tet containing the edge. //
19155 // //
19156 // This edge may intersect a set of faces and edges in the mesh. All these //
19157 // faces or edges are needed to be removed. //
19158 // //
19159 // If the parameter 'fullsearch' is set, it tries to flip any face or edge //
19160 // that intersects the recovering edge. Otherwise, only the face or edge //
19161 // which is visible by 'startpt' is tried. //
19162 // //
19163 // The parameter 'sedge' is used to report self-intersection. If it is not //
19164 // a NULL, it is EITHER a segment OR a subface that contains this edge. //
19165 // //
19166 // Note that this routine assumes that the tetrahedralization is convex. //
19167 // //
19169 
19170 int tetgenmesh::recoveredgebyflips(point startpt, point endpt, face *sedge,
19171  triface* searchtet, int fullsearch)
19172 {
19173  flipconstraints fc;
19174  enum interresult dir;
19175 
19176  fc.seg[0] = startpt;
19177  fc.seg[1] = endpt;
19178  fc.checkflipeligibility = 1;
19179 
19180  // The mainloop of the edge reocvery.
19181  while (1) { // Loop I
19182 
19183  // Search the edge from 'startpt'.
19184  point2tetorg(startpt, *searchtet);
19185  dir = finddirection(searchtet, endpt);
19186  if (dir == ACROSSVERT) {
19187  if (dest(*searchtet) == endpt) {
19188  return 1; // Edge is recovered.
19189  } else {
19190  if (sedge) {
19191  return report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
19192  } else {
19193  return 0;
19194  }
19195  }
19196  }
19197 
19198  // The edge is missing.
19199 
19200  // Try to remove the first intersecting face/edge.
19201  enextesymself(*searchtet); // Go to the opposite face.
19202  if (dir == ACROSSFACE) {
19203  if (checksubfaceflag) {
19204  if (issubface(*searchtet)) {
19205  if (sedge) {
19206  return report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
19207  } else {
19208  return 0; // Cannot flip a subface.
19209  }
19210  }
19211  }
19212  // Try to flip a crossing face.
19213  if (removefacebyflips(searchtet, &fc)) {
19214  continue;
19215  }
19216  } else if (dir == ACROSSEDGE) {
19217  if (checksubsegflag) {
19218  if (issubseg(*searchtet)) {
19219  if (sedge) {
19220  return report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
19221  } else {
19222  return 0; // Cannot flip a segment.
19223  }
19224  }
19225  }
19226  // Try to flip an intersecting edge.
19227  if (removeedgebyflips(searchtet, &fc) == 2) {
19228  continue;
19229  }
19230  }
19231 
19232  // The edge is missing.
19233 
19234  if (fullsearch) {
19235  // Try to flip one of the faces/edges which intersects the edge.
19236  triface neightet, spintet;
19237  point pa, pb, pc, pd;
19238  badface bakface;
19239  enum interresult dir1;
19240  int types[2], poss[4], pos = 0;
19241  int success = 0;
19242  int t1ver;
19243  int i, j;
19244 
19245  // Loop through the sequence of intersecting faces/edges from
19246  // 'startpt' to 'endpt'.
19247  point2tetorg(startpt, *searchtet);
19248  dir = finddirection(searchtet, endpt);
19249 
19250  // Go to the face/edge intersecting the searching edge.
19251  enextesymself(*searchtet); // Go to the opposite face.
19252  // This face/edge has been tried in previous step.
19253 
19254  while (1) { // Loop I-I
19255 
19256  // Find the next intersecting face/edge.
19257  fsymself(*searchtet);
19258  if (dir == ACROSSFACE) {
19259  neightet = *searchtet;
19260  j = (neightet.ver & 3); // j is the current face number.
19261  for (i = j + 1; i < j + 4; i++) {
19262  neightet.ver = (i % 4);
19263  pa = org(neightet);
19264  pb = dest(neightet);
19265  pc = apex(neightet);
19266  pd = oppo(neightet); // The above point.
19267  if (tri_edge_test(pa,pb,pc,startpt,endpt, pd, 1, types, poss)) {
19268  dir = (enum interresult) types[0];
19269  pos = poss[0];
19270  break;
19271  } else {
19272  dir = DISJOINT;
19273  pos = 0;
19274  }
19275  } // i
19276  // There must be an intersection face/edge.
19277  if (dir == DISJOINT) {
19278  terminatetetgen(this, 2);
19279  }
19280  } else if (dir == ACROSSEDGE) {
19281  while (1) { // Loop I-I-I
19282  // Check the two opposite faces (of the edge) in 'searchtet'.
19283  for (i = 0; i < 2; i++) {
19284  if (i == 0) {
19285  enextesym(*searchtet, neightet);
19286  } else {
19287  eprevesym(*searchtet, neightet);
19288  }
19289  pa = org(neightet);
19290  pb = dest(neightet);
19291  pc = apex(neightet);
19292  pd = oppo(neightet); // The above point.
19293  if (tri_edge_test(pa,pb,pc,startpt,endpt,pd,1, types, poss)) {
19294  dir = (enum interresult) types[0];
19295  pos = poss[0];
19296  break; // for loop
19297  } else {
19298  dir = DISJOINT;
19299  pos = 0;
19300  }
19301  } // i
19302  if (dir != DISJOINT) {
19303  // Find an intersection face/edge.
19304  break; // Loop I-I-I
19305  }
19306  // No intersection. Rotate to the next tet at the edge.
19307  fnextself(*searchtet);
19308  } // while (1) // Loop I-I-I
19309  } else {
19310  terminatetetgen(this, 2); // Report a bug
19311  }
19312 
19313  // Adjust to the intersecting edge/vertex.
19314  for (i = 0; i < pos; i++) {
19315  enextself(neightet);
19316  }
19317 
19318  if (dir == SHAREVERT) {
19319  // Check if we have reached the 'endpt'.
19320  pd = org(neightet);
19321  if (pd == endpt) {
19322  // Failed to recover the edge.
19323  break; // Loop I-I
19324  } else {
19325  terminatetetgen(this, 2); // Report a bug
19326  }
19327  }
19328 
19329  // The next to be flipped face/edge.
19330  *searchtet = neightet;
19331 
19332  // Bakup this face (tetrahedron).
19333  bakface.forg = org(*searchtet);
19334  bakface.fdest = dest(*searchtet);
19335  bakface.fapex = apex(*searchtet);
19336  bakface.foppo = oppo(*searchtet);
19337 
19338  // Try to flip this intersecting face/edge.
19339  if (dir == ACROSSFACE) {
19340  if (checksubfaceflag) {
19341  if (issubface(*searchtet)) {
19342  if (sedge) {
19343  return report_selfint_edge(startpt,endpt,sedge,searchtet,dir);
19344  } else {
19345  return 0; // Cannot flip a subface.
19346  }
19347  }
19348  }
19349  if (removefacebyflips(searchtet, &fc)) {
19350  success = 1;
19351  break; // Loop I-I
19352  }
19353  } else if (dir == ACROSSEDGE) {
19354  if (checksubsegflag) {
19355  if (issubseg(*searchtet)) {
19356  if (sedge) {
19357  return report_selfint_edge(startpt,endpt,sedge,searchtet,dir);
19358  } else {
19359  return 0; // Cannot flip a segment.
19360  }
19361  }
19362  }
19363  if (removeedgebyflips(searchtet, &fc) == 2) {
19364  success = 1;
19365  break; // Loop I-I
19366  }
19367  } else if (dir == ACROSSVERT) {
19368  if (sedge) {
19369  //return report_selfint_edge(startpt, endpt, sedge, searchtet, dir);
19370  terminatetetgen(this, 2);
19371  } else {
19372  return 0;
19373  }
19374  } else {
19375  terminatetetgen(this, 2);
19376  }
19377 
19378  // The face/edge is not flipped.
19379  if ((searchtet->tet == NULL) ||
19380  (org(*searchtet) != bakface.forg) ||
19381  (dest(*searchtet) != bakface.fdest) ||
19382  (apex(*searchtet) != bakface.fapex) ||
19383  (oppo(*searchtet) != bakface.foppo)) {
19384  // 'searchtet' was flipped. We must restore it.
19385  point2tetorg(bakface.forg, *searchtet);
19386  dir1 = finddirection(searchtet, bakface.fdest);
19387  if (dir1 == ACROSSVERT) {
19388  if (dest(*searchtet) == bakface.fdest) {
19389  spintet = *searchtet;
19390  while (1) {
19391  if (apex(spintet) == bakface.fapex) {
19392  // Found the face.
19393  *searchtet = spintet;
19394  break;
19395  }
19396  fnextself(spintet);
19397  if (spintet.tet == searchtet->tet) {
19398  searchtet->tet = NULL;
19399  break; // Not find.
19400  }
19401  } // while (1)
19402  if (searchtet->tet != NULL) {
19403  if (oppo(*searchtet) != bakface.foppo) {
19404  fsymself(*searchtet);
19405  if (oppo(*searchtet) != bakface.foppo) {
19406  // The original (intersecting) tet has been flipped.
19407  searchtet->tet = NULL;
19408  break; // Not find.
19409  }
19410  }
19411  }
19412  } else {
19413  searchtet->tet = NULL; // Not find.
19414  }
19415  } else {
19416  searchtet->tet = NULL; // Not find.
19417  }
19418  if (searchtet->tet == NULL) {
19419  success = 0; // This face/edge has been destroyed.
19420  break; // Loop I-I
19421  }
19422  }
19423  } // while (1) // Loop I-I
19424 
19425  if (success) {
19426  // One of intersecting faces/edges is flipped.
19427  continue;
19428  }
19429 
19430  } // if (fullsearch)
19431 
19432  // The edge is missing.
19433  break; // Loop I
19434 
19435  } // while (1) // Loop I
19436 
19437  return 0;
19438 }
19439 
19441 // //
19442 // add_steinerpt_in_schoenhardtpoly() Insert a Steiner point in a Schoen- //
19443 // hardt polyhedron. //
19444 // //
19445 // 'abtets' is an array of n tets which all share at the edge [a,b]. Let the //
19446 // tets are [a,b,p0,p1], [a,b,p1,p2], ..., [a,b,p_(n-2),p_(n-1)]. Moreover, //
19447 // the edge [p0,p_(n-1)] intersects all of the tets in 'abtets'. A special //
19448 // case is that the edge [p0,p_(n-1)] is coplanar with the edge [a,b]. //
19449 // Such set of tets arises when we want to recover an edge from 'p0' to 'p_ //
19450 // (n-1)', and the number of tets at [a,b] can not be reduced by any flip. //
19451 // //
19453 
19454 int tetgenmesh::add_steinerpt_in_schoenhardtpoly(triface *abtets, int n,
19455  int chkencflag)
19456 {
19457  triface worktet, *parytet;
19458  triface faketet1, faketet2;
19459  point pc, pd, steinerpt;
19460  insertvertexflags ivf;
19461  optparameters opm;
19462  REAL vcd[3], sampt[3], smtpt[3];
19463  REAL maxminvol = 0.0, minvol = 0.0, ori;
19464  int success, maxidx = 0;
19465  int it, i;
19466 
19467 
19468  pc = apex(abtets[0]); // pc = p0
19469  pd = oppo(abtets[n-1]); // pd = p_(n-1)
19470 
19471 
19472  // Find an optimial point in edge [c,d]. It is visible by all outer faces
19473  // of 'abtets', and it maxmizes the min volume.
19474 
19475  // initialize the list of 2n boundary faces.
19476  for (i = 0; i < n; i++) {
19477  edestoppo(abtets[i], worktet); // [p_i,p_i+1,a]
19478  cavetetlist->newindex((void **) &parytet);
19479  *parytet = worktet;
19480  eorgoppo(abtets[i], worktet); // [p_i+1,p_i,b]
19481  cavetetlist->newindex((void **) &parytet);
19482  *parytet = worktet;
19483  }
19484 
19485  int N = 100;
19486  REAL stepi = 0.01;
19487 
19488  // Search the point along the edge [c,d].
19489  for (i = 0; i < 3; i++) vcd[i] = pd[i] - pc[i];
19490 
19491  // Sample N points in edge [c,d].
19492  for (it = 1; it < N; it++) {
19493  for (i = 0; i < 3; i++) {
19494  sampt[i] = pc[i] + (stepi * (double) it) * vcd[i];
19495  }
19496  for (i = 0; i < cavetetlist->objects; i++) {
19497  parytet = (triface *) fastlookup(cavetetlist, i);
19498  ori = orient3d(dest(*parytet), org(*parytet), apex(*parytet), sampt);
19499  if (i == 0) {
19500  minvol = ori;
19501  } else {
19502  if (minvol > ori) minvol = ori;
19503  }
19504  } // i
19505  if (it == 1) {
19506  maxminvol = minvol;
19507  maxidx = it;
19508  } else {
19509  if (maxminvol < minvol) {
19510  maxminvol = minvol;
19511  maxidx = it;
19512  }
19513  }
19514  } // it
19515 
19516  if (maxminvol <= 0) {
19517  cavetetlist->restart();
19518  return 0;
19519  }
19520 
19521  for (i = 0; i < 3; i++) {
19522  smtpt[i] = pc[i] + (stepi * (double) maxidx) * vcd[i];
19523  }
19524 
19525  // Create two faked tets to hold the two non-existing boundary faces:
19526  // [d,c,a] and [c,d,b].
19527  maketetrahedron(&faketet1);
19528  setvertices(faketet1, pd, pc, org(abtets[0]), dummypoint);
19529  cavetetlist->newindex((void **) &parytet);
19530  *parytet = faketet1;
19531  maketetrahedron(&faketet2);
19532  setvertices(faketet2, pc, pd, dest(abtets[0]), dummypoint);
19533  cavetetlist->newindex((void **) &parytet);
19534  *parytet = faketet2;
19535 
19536  // Point smooth options.
19537  opm.max_min_volume = 1;
19538  opm.numofsearchdirs = 20;
19539  opm.searchstep = 0.001;
19540  opm.maxiter = 100; // Limit the maximum iterations.
19541  opm.initval = 0.0; // Initial volume is zero.
19542 
19543  // Try to relocate the point into the inside of the polyhedron.
19544  success = smoothpoint(smtpt, cavetetlist, 1, &opm);
19545 
19546  if (success) {
19547  while (opm.smthiter == 100) {
19548  // It was relocated and the prescribed maximum iteration reached.
19549  // Try to increase the search stepsize.
19550  opm.searchstep *= 10.0;
19551  //opm.maxiter = 100; // Limit the maximum iterations.
19552  opm.initval = opm.imprval;
19553  opm.smthiter = 0; // Init.
19554  smoothpoint(smtpt, cavetetlist, 1, &opm);
19555  }
19556  } // if (success)
19557 
19558  // Delete the two faked tets.
19559  tetrahedrondealloc(faketet1.tet);
19560  tetrahedrondealloc(faketet2.tet);
19561 
19562  cavetetlist->restart();
19563 
19564  if (!success) {
19565  return 0;
19566  }
19567 
19568 
19569  // Insert the Steiner point.
19570  makepoint(&steinerpt, FREEVOLVERTEX);
19571  for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i];
19572 
19573  // Insert the created Steiner point.
19574  for (i = 0; i < n; i++) {
19575  infect(abtets[i]);
19576  caveoldtetlist->newindex((void **) &parytet);
19577  *parytet = abtets[i];
19578  }
19579  worktet = abtets[0]; // No need point location.
19580  ivf.iloc = (int) INSTAR;
19581  ivf.chkencflag = chkencflag;
19582  ivf.assignmeshsize = b->metric;
19583  if (ivf.assignmeshsize) {
19584  // Search the tet containing 'steinerpt' for size interpolation.
19585  locate(steinerpt, &(abtets[0]));
19586  worktet = abtets[0];
19587  }
19588 
19589  // Insert the new point into the tetrahedralization T.
19590  // Note that T is convex (nonconvex = 0).
19591  if (insertpoint(steinerpt, &worktet, NULL, NULL, &ivf)) {
19592  // The vertex has been inserted.
19593  st_volref_count++;
19594  if (steinerleft > 0) steinerleft--;
19595  return 1;
19596  } else {
19597  // Not inserted.
19598  pointdealloc(steinerpt);
19599  return 0;
19600  }
19601 }
19602 
19604 // //
19605 // add_steinerpt_in_segment() Add a Steiner point inside a segment. //
19606 // //
19608 
19609 int tetgenmesh::add_steinerpt_in_segment(face* misseg, int searchlevel)
19610 {
19611  triface searchtet;
19612  face *paryseg, candseg;
19613  point startpt, endpt, pc, pd;
19614  flipconstraints fc;
19615  enum interresult dir;
19616  REAL P[3], Q[3], tp, tq;
19617  REAL len, smlen = 0, split = 0, split_q = 0;
19618  #pragma GCC diagnostic push
19619  #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
19620  int success;
19621  #pragma GCC diagnostic pop
19622  int i;
19623 
19624  startpt = sorg(*misseg);
19625  endpt = sdest(*misseg);
19626 
19627  fc.seg[0] = startpt;
19628  fc.seg[1] = endpt;
19629  fc.checkflipeligibility = 1;
19630  fc.collectencsegflag = 1;
19631 
19632  point2tetorg(startpt, searchtet);
19633  dir = finddirection(&searchtet, endpt);
19634  // Try to flip the first intersecting face/edge.
19635  enextesymself(searchtet); // Go to the opposite face.
19636 
19637  int bak_fliplinklevel = b->fliplinklevel;
19638  b->fliplinklevel = searchlevel;
19639 
19640  if (dir == ACROSSFACE) {
19641  // A face is intersected with the segment. Try to flip it.
19642  success = removefacebyflips(&searchtet, &fc);
19643  } else if (dir == ACROSSEDGE) {
19644  // An edge is intersected with the segment. Try to flip it.
19645  success = removeedgebyflips(&searchtet, &fc);
19646  }
19647 
19648  split = 0;
19649  for (i = 0; i < caveencseglist->objects; i++) {
19650  paryseg = (face *) fastlookup(caveencseglist, i);
19651  suninfect(*paryseg);
19652  // Calculate the shortest edge between the two lines.
19653  pc = sorg(*paryseg);
19654  pd = sdest(*paryseg);
19655  tp = tq = 0;
19656  if (linelineint(startpt, endpt, pc, pd, P, Q, &tp, &tq)) {
19657  // Does the shortest edge lie between the two segments?
19658  // Round tp and tq.
19659  if ((tp > 0) && (tq < 1)) {
19660  if (tp < 0.5) {
19661  if (tp < (b->epsilon * 1e+3)) tp = 0.0;
19662  } else {
19663  if ((1.0 - tp) < (b->epsilon * 1e+3)) tp = 1.0;
19664  }
19665  }
19666  if ((tp <= 0) || (tp >= 1)) continue;
19667  if ((tq > 0) && (tq < 1)) {
19668  if (tq < 0.5) {
19669  if (tq < (b->epsilon * 1e+3)) tq = 0.0;
19670  } else {
19671  if ((1.0 - tq) < (b->epsilon * 1e+3)) tq = 1.0;
19672  }
19673  }
19674  if ((tq <= 0) || (tq >= 1)) continue;
19675  // It is a valid shortest edge. Calculate its length.
19676  len = distance(P, Q);
19677  if (split == 0) {
19678  smlen = len;
19679  split = tp;
19680  split_q = tq;
19681  candseg = *paryseg;
19682  } else {
19683  if (len < smlen) {
19684  smlen = len;
19685  split = tp;
19686  split_q = tq;
19687  candseg = *paryseg;
19688  }
19689  }
19690  }
19691  }
19692 
19693  caveencseglist->restart();
19694  b->fliplinklevel = bak_fliplinklevel;
19695 
19696  if (split == 0) {
19697  // Found no crossing segment.
19698  return 0;
19699  }
19700 
19701  face splitsh;
19702  face splitseg;
19703  point steinerpt, *parypt;
19704  insertvertexflags ivf;
19705 
19706  if (b->addsteiner_algo == 1) {
19707  // Split the segment at the closest point to a near segment.
19708  makepoint(&steinerpt, FREESEGVERTEX);
19709  for (i = 0; i < 3; i++) {
19710  steinerpt[i] = startpt[i] + split * (endpt[i] - startpt[i]);
19711  }
19712  } else { // b->addsteiner_algo == 2
19713  for (i = 0; i < 3; i++) {
19714  P[i] = startpt[i] + split * (endpt[i] - startpt[i]);
19715  }
19716  pc = sorg(candseg);
19717  pd = sdest(candseg);
19718  for (i = 0; i < 3; i++) {
19719  Q[i] = pc[i] + split_q * (pd[i] - pc[i]);
19720  }
19721  makepoint(&steinerpt, FREEVOLVERTEX);
19722  for (i = 0; i < 3; i++) {
19723  steinerpt[i] = 0.5 * (P[i] + Q[i]);
19724  }
19725  }
19726 
19727  // We need to locate the point. Start searching from 'searchtet'.
19728  if (split < 0.5) {
19729  point2tetorg(startpt, searchtet);
19730  } else {
19731  point2tetorg(endpt, searchtet);
19732  }
19733  if (b->addsteiner_algo == 1) {
19734  splitseg = *misseg;
19735  spivot(*misseg, splitsh);
19736  } else {
19737  splitsh.sh = NULL;
19738  splitseg.sh = NULL;
19739  }
19740  ivf.iloc = (int) OUTSIDE;
19741  ivf.bowywat = 1;
19742  ivf.lawson = 0;
19743  ivf.rejflag = 0;
19744  ivf.chkencflag = 0;
19745  ivf.sloc = (int) ONEDGE;
19746  ivf.sbowywat = 1;
19747  ivf.splitbdflag = 0;
19748  ivf.validflag = 1;
19749  ivf.respectbdflag = 1;
19750  ivf.assignmeshsize = b->metric;
19751 
19752  if (!insertpoint(steinerpt, &searchtet, &splitsh, &splitseg, &ivf)) {
19753  pointdealloc(steinerpt);
19754  return 0;
19755  }
19756 
19757  if (b->addsteiner_algo == 1) {
19758  // Save this Steiner point (for removal).
19759  // Re-use the array 'subvertstack'.
19760  subvertstack->newindex((void **) &parypt);
19761  *parypt = steinerpt;
19762  st_segref_count++;
19763  } else { // b->addsteiner_algo == 2
19764  // Queue the segment for recovery.
19765  subsegstack->newindex((void **) &paryseg);
19766  *paryseg = *misseg;
19767  st_volref_count++;
19768  }
19769  if (steinerleft > 0) steinerleft--;
19770 
19771  return 1;
19772 }
19773 
19775 // //
19776 // addsteiner4recoversegment() Add a Steiner point for recovering a seg. //
19777 // //
19779 
19780 int tetgenmesh::addsteiner4recoversegment(face* misseg, int splitsegflag)
19781 {
19782  triface *abtets, searchtet, spintet;
19783  face splitsh;
19784  face *paryseg;
19785  point startpt, endpt;
19786  point pa, pb, pd, steinerpt, *parypt;
19787  enum interresult dir;
19788  insertvertexflags ivf;
19789  int types[2], poss[4];
19790  int n, endi, success;
19791  int t1ver;
19792  int i;
19793 
19794  startpt = sorg(*misseg);
19795  if (pointtype(startpt) == FREESEGVERTEX) {
19796  sesymself(*misseg);
19797  startpt = sorg(*misseg);
19798  }
19799  endpt = sdest(*misseg);
19800 
19801  // Try to recover the edge by adding Steiner points.
19802  point2tetorg(startpt, searchtet);
19803  dir = finddirection(&searchtet, endpt);
19804  enextself(searchtet);
19805 
19806  if (dir == ACROSSFACE) {
19807  // The segment is crossing at least 3 faces. Find the common edge of
19808  // the first 3 crossing faces.
19809  esymself(searchtet);
19810  fsym(searchtet, spintet);
19811  pd = oppo(spintet);
19812  for (i = 0; i < 3; i++) {
19813  pa = org(spintet);
19814  pb = dest(spintet);
19815  if (tri_edge_test(pa, pb, pd, startpt, endpt, NULL, 1, types, poss)) {
19816  break; // Found the edge.
19817  }
19818  enextself(spintet);
19819  eprevself(searchtet);
19820  }
19821  esymself(searchtet);
19822  }
19823 
19824  spintet = searchtet;
19825  n = 0; endi = -1;
19826  while (1) {
19827  // Check if the endpt appears in the star.
19828  if (apex(spintet) == endpt) {
19829  endi = n; // Remember the position of endpt.
19830  }
19831  n++; // Count a tet in the star.
19832  fnextself(spintet);
19833  if (spintet.tet == searchtet.tet) break;
19834  }
19835 
19836  if (endi > 0) {
19837  // endpt is also in the edge star
19838  // Get all tets in the edge star.
19839  abtets = new triface[n];
19840  spintet = searchtet;
19841  for (i = 0; i < n; i++) {
19842  abtets[i] = spintet;
19843  fnextself(spintet);
19844  }
19845 
19846  success = 0;
19847 
19848  if (dir == ACROSSFACE) {
19849  // Find a Steiner points inside the polyhedron.
19850  if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) {
19851  success = 1;
19852  }
19853  } else if (dir == ACROSSEDGE) {
19854  // PLC check.
19855  if (issubseg(searchtet)) {
19856  terminatetetgen(this, 2);
19857  }
19858  if (n > 4) {
19859  // In this case, 'abtets' is separated by the plane (containing the
19860  // two intersecting edges) into two parts, P1 and P2, where P1
19861  // consists of 'endi' tets: abtets[0], abtets[1], ...,
19862  // abtets[endi-1], and P2 consists of 'n - endi' tets:
19863  // abtets[endi], abtets[endi+1], abtets[n-1].
19864  if (endi > 2) { // P1
19865  // There are at least 3 tets in the first part.
19866  if (add_steinerpt_in_schoenhardtpoly(abtets, endi, 0)) {
19867  success++;
19868  }
19869  }
19870  if ((n - endi) > 2) { // P2
19871  // There are at least 3 tets in the first part.
19872  if (add_steinerpt_in_schoenhardtpoly(&(abtets[endi]), n - endi, 0)) {
19873  success++;
19874  }
19875  }
19876  } else {
19877  // In this case, a 4-to-4 flip should be re-cover the edge [c,d].
19878  // However, there will be invalid tets (either zero or negtive
19879  // volume). Otherwise, [c,d] should already be recovered by the
19880  // recoveredge() function.
19881  terminatetetgen(this, 2);
19882  }
19883  } else {
19884  terminatetetgen(this, 2);
19885  }
19886 
19887  delete [] abtets;
19888 
19889  if (success) {
19890  // Add the missing segment back to the recovering list.
19891  subsegstack->newindex((void **) &paryseg);
19892  *paryseg = *misseg;
19893  return 1;
19894  }
19895  } // if (endi > 0)
19896 
19897  if (!splitsegflag) {
19898  return 0;
19899  }
19900 
19901  if (b->verbose > 2) {
19902  printf(" Splitting segment (%d, %d)\n", pointmark(startpt),
19903  pointmark(endpt));
19904  }
19905  steinerpt = NULL;
19906 
19907  if (b->addsteiner_algo > 0) { // -Y/1 or -Y/2
19908  if (add_steinerpt_in_segment(misseg, 3)) {
19909  return 1;
19910  }
19911  sesymself(*misseg);
19912  if (add_steinerpt_in_segment(misseg, 3)) {
19913  return 1;
19914  }
19915  sesymself(*misseg);
19916  }
19917 
19918 
19919 
19920 
19921  if (steinerpt == NULL) {
19922  // Split the segment at its midpoint.
19923  makepoint(&steinerpt, FREESEGVERTEX);
19924  for (i = 0; i < 3; i++) {
19925  steinerpt[i] = 0.5 * (startpt[i] + endpt[i]);
19926  }
19927 
19928  // We need to locate the point.
19929  spivot(*misseg, splitsh);
19930  ivf.iloc = (int) OUTSIDE;
19931  ivf.bowywat = 1;
19932  ivf.lawson = 0;
19933  ivf.rejflag = 0;
19934  ivf.chkencflag = 0;
19935  ivf.sloc = (int) ONEDGE;
19936  ivf.sbowywat = 1;
19937  ivf.splitbdflag = 0;
19938  ivf.validflag = 1;
19939  ivf.respectbdflag = 1;
19940  ivf.assignmeshsize = b->metric;
19941  if (!insertpoint(steinerpt, &searchtet, &splitsh, misseg, &ivf)) {
19942  terminatetetgen(this, 2);
19943  }
19944  } // if (endi > 0)
19945 
19946  // Save this Steiner point (for removal).
19947  // Re-use the array 'subvertstack'.
19948  subvertstack->newindex((void **) &parypt);
19949  *parypt = steinerpt;
19950 
19951  st_segref_count++;
19952  if (steinerleft > 0) steinerleft--;
19953 
19954  return 1;
19955 }
19956 
19958 // //
19959 // recoversegments() Recover all segments. //
19960 // //
19961 // All segments need to be recovered are in 'subsegstack'. //
19962 // //
19963 // This routine first tries to recover each segment by only using flips. If //
19964 // no flip is possible, and the flag 'steinerflag' is set, it then tries to //
19965 // insert Steiner points near or in the segment. //
19966 // //
19968 
19969 int tetgenmesh::recoversegments(arraypool *misseglist, int fullsearch,
19970  int steinerflag)
19971 {
19972  triface searchtet, spintet;
19973  face sseg, *paryseg;
19974  point startpt, endpt;
19975  int success;
19976  int t1ver;
19977 
19978  long bak_inpoly_count = st_volref_count;
19979  long bak_segref_count = st_segref_count;
19980 
19981  if (b->verbose > 1) {
19982  printf(" Recover segments [%s level = %2d] #: %ld.\n",
19983  (b->fliplinklevel > 0) ? "fixed" : "auto",
19984  (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
19985  subsegstack->objects);
19986  }
19987 
19988  // Loop until 'subsegstack' is empty.
19989  while (subsegstack->objects > 0l) {
19990  // seglist is used as a stack.
19991  subsegstack->objects--;
19992  paryseg = (face *) fastlookup(subsegstack, subsegstack->objects);
19993  sseg = *paryseg;
19994 
19995  // Check if this segment has been recovered.
19996  sstpivot1(sseg, searchtet);
19997  if (searchtet.tet != NULL) {
19998  continue; // Not a missing segment.
19999  }
20000 
20001  startpt = sorg(sseg);
20002  endpt = sdest(sseg);
20003 
20004  if (b->verbose > 2) {
20005  printf(" Recover segment (%d, %d).\n", pointmark(startpt),
20006  pointmark(endpt));
20007  }
20008 
20009  success = 0;
20010 
20011  if (recoveredgebyflips(startpt, endpt, &sseg, &searchtet, 0)) {
20012  success = 1;
20013  } else {
20014  // Try to recover it from the other direction.
20015  if (recoveredgebyflips(endpt, startpt, &sseg, &searchtet, 0)) {
20016  success = 1;
20017  }
20018  }
20019 
20020  if (!success && fullsearch) {
20021  if (recoveredgebyflips(startpt, endpt, &sseg, &searchtet, fullsearch)) {
20022  success = 1;
20023  }
20024  }
20025 
20026  if (success) {
20027  // Segment is recovered. Insert it.
20028  // Let the segment remember an adjacent tet.
20029  sstbond1(sseg, searchtet);
20030  // Bond the segment to all tets containing it.
20031  spintet = searchtet;
20032  do {
20033  tssbond1(spintet, sseg);
20034  fnextself(spintet);
20035  } while (spintet.tet != searchtet.tet);
20036  } else {
20037  if (steinerflag > 0) {
20038  // Try to recover the segment but do not split it.
20039  if (addsteiner4recoversegment(&sseg, 0)) {
20040  success = 1;
20041  }
20042  if (!success && (steinerflag > 1)) {
20043  // Split the segment.
20044  addsteiner4recoversegment(&sseg, 1);
20045  success = 1;
20046  }
20047  }
20048  if (!success) {
20049  if (misseglist != NULL) {
20050  // Save this segment.
20051  misseglist->newindex((void **) &paryseg);
20052  *paryseg = sseg;
20053  }
20054  }
20055  }
20056 
20057  } // while (subsegstack->objects > 0l)
20058 
20059  if (steinerflag) {
20060  if (b->verbose > 1) {
20061  // Report the number of added Steiner points.
20062  if (st_volref_count > bak_inpoly_count) {
20063  printf(" Add %ld Steiner points in volume.\n",
20064  st_volref_count - bak_inpoly_count);
20065  }
20066  if (st_segref_count > bak_segref_count) {
20067  printf(" Add %ld Steiner points in segments.\n",
20068  st_segref_count - bak_segref_count);
20069  }
20070  }
20071  }
20072 
20073  return 0;
20074 }
20075 
20077 // //
20078 // recoverfacebyflips() Recover a face by flips. //
20079 // //
20080 // 'pa', 'pb', and 'pc' are the three vertices of this face. This routine //
20081 // tries to recover it in the tetrahedral mesh. It is assumed that the three //
20082 // edges, i.e., pa->pb, pb->pc, and pc->pa all exist. //
20083 // //
20084 // If the face is recovered, it is returned by 'searchtet'. //
20085 // //
20086 // If 'searchsh' is not NULL, it is a subface to be recovered. Its vertices //
20087 // must be pa, pb, and pc. It is mainly used to check self-intersections. //
20088 // Another use of this subface is to split it when a Steiner point is found //
20089 // inside this subface. //
20090 // //
20092 
20093 int tetgenmesh::recoverfacebyflips(point pa, point pb, point pc,
20094  face *searchsh, triface* searchtet)
20095 {
20096  triface spintet, flipedge;
20097  point pd, pe;
20098  flipconstraints fc;
20099  int types[2], poss[4], intflag;
20100  int success;
20101  int t1ver;
20102  int i, j;
20103 
20104 
20105  fc.fac[0] = pa;
20106  fc.fac[1] = pb;
20107  fc.fac[2] = pc;
20108  fc.checkflipeligibility = 1;
20109  success = 0;
20110 
20111  for (i = 0; i < 3 && !success; i++) {
20112  while (1) {
20113  // Get a tet containing the edge [a,b].
20114  point2tetorg(fc.fac[i], *searchtet);
20115  finddirection(searchtet, fc.fac[(i+1)%3]);
20116  // Search the face [a,b,c]
20117  spintet = *searchtet;
20118  while (1) {
20119  if (apex(spintet) == fc.fac[(i+2)%3]) {
20120  // Found the face.
20121  *searchtet = spintet;
20122  // Return the face [a,b,c].
20123  for (j = i; j > 0; j--) {
20124  eprevself(*searchtet);
20125  }
20126  success = 1;
20127  break;
20128  }
20129  fnextself(spintet);
20130  if (spintet.tet == searchtet->tet) break;
20131  } // while (1)
20132  if (success) break;
20133  // The face is missing. Try to recover it.
20134  flipedge.tet = NULL;
20135  // Find a crossing edge of this face.
20136  spintet = *searchtet;
20137  while (1) {
20138  pd = apex(spintet);
20139  pe = oppo(spintet);
20140  if ((pd != dummypoint) && (pe != dummypoint)) {
20141  // Check if [d,e] intersects [a,b,c]
20142  intflag = tri_edge_test(pa, pb, pc, pd, pe, NULL, 1, types, poss);
20143  if (intflag > 0) {
20144  // By the assumption that all edges of the face exist, they can
20145  // only intersect at a single point.
20146  if (intflag == 2) {
20147  // Go to the edge [d,e].
20148  edestoppo(spintet, flipedge); // [d,e,a,b]
20149  if (searchsh != NULL) {
20150  // Check the intersection type.
20151  if ((types[0] == (int) ACROSSFACE) ||
20152  (types[0] == (int) ACROSSEDGE)) {
20153  // Check if [e,d] is a segment.
20154  if (issubseg(flipedge)) {
20155  return report_selfint_face(pa, pb, pc, searchsh, &flipedge,
20156  intflag, types, poss);
20157  } else {
20158  // Check if [e,d] is an edge of a subface.
20159  triface chkface = flipedge;
20160  while (1) {
20161  if (issubface(chkface)) break;
20162  fsymself(chkface);
20163  if (chkface.tet == flipedge.tet) break;
20164  }
20165  if (issubface(chkface)) {
20166  // Two subfaces are intersecting.
20167  return report_selfint_face(pa, pb, pc,searchsh,&chkface,
20168  intflag, types, poss);
20169  }
20170  }
20171  } else if (types[0] == TOUCHFACE) {
20172  // This is possible when a Steiner point was added on it.
20173  point touchpt, *parypt;
20174  if (poss[1] == 0) {
20175  touchpt = pd; // pd is a coplanar vertex.
20176  } else {
20177  touchpt = pe; // pe is a coplanar vertex.
20178  }
20179  if (pointtype(touchpt) == FREEVOLVERTEX) {
20180  // A volume Steiner point was added in this subface.
20181  // Split this subface by this point.
20182  face checksh, *parysh;
20183  int siloc = (int) ONFACE;
20184  int sbowat = 0; // Only split this subface. A 1-to-3 flip.
20185  setpointtype(touchpt, FREEFACETVERTEX);
20186  sinsertvertex(touchpt, searchsh, NULL, siloc, sbowat, 0);
20187  st_volref_count--;
20188  st_facref_count++;
20189  // Queue this vertex for removal.
20190  subvertstack->newindex((void **) &parypt);
20191  *parypt = touchpt;
20192  // Queue new subfaces for recovery.
20193  // Put all new subfaces into stack for recovery.
20194  for (i = 0; i < caveshbdlist->objects; i++) {
20195  // Get an old subface at edge [a, b].
20196  parysh = (face *) fastlookup(caveshbdlist, i);
20197  spivot(*parysh, checksh); // The new subface [a, b, p].
20198  // Do not recover a deleted new face (degenerated).
20199  if (checksh.sh[3] != NULL) {
20200  subfacstack->newindex((void **) &parysh);
20201  *parysh = checksh;
20202  }
20203  }
20204  // Delete the old subfaces in sC(p).
20205  for (i = 0; i < caveshlist->objects; i++) {
20206  parysh = (face *) fastlookup(caveshlist, i);
20207  shellfacedealloc(subfaces, parysh->sh);
20208  }
20209  // Clear working lists.
20210  caveshlist->restart();
20211  caveshbdlist->restart();
20212  cavesegshlist->restart();
20213  // We can return this function.
20214  searchsh->sh = NULL; // It has been split.
20215  return 1;
20216  } else {
20217  // Other cases may be due to a bug or a PLC error.
20218  return report_selfint_face(pa, pb, pc, searchsh, &flipedge,
20219  intflag, types, poss);
20220  }
20221  } else {
20222  // The other intersection types: ACROSSVERT, TOUCHEDGE,
20223  // SHAREVERTEX should not be possible or due to a PLC error.
20224  return report_selfint_face(pa, pb, pc, searchsh, &flipedge,
20225  intflag, types, poss);
20226  }
20227  } // if (searchsh != NULL)
20228  } else { // intflag == 4. Coplanar case.
20229  terminatetetgen(this, 2);
20230  }
20231  break;
20232  } // if (intflag > 0)
20233  }
20234  fnextself(spintet);
20235  if (spintet.tet == searchtet->tet) {
20236  terminatetetgen(this, 2);
20237  }
20238  } // while (1)
20239  // Try to flip the edge [d,e].
20240  if (removeedgebyflips(&flipedge, &fc) == 2) {
20241  // A crossing edge is removed.
20242  continue;
20243  }
20244  break;
20245  } // while (1)
20246  } // i
20247 
20248  return success;
20249 }
20250 
20252 // //
20253 // recoversubfaces() Recover all subfaces. //
20254 // //
20256 
20257 int tetgenmesh::recoversubfaces(arraypool *misshlist, int steinerflag)
20258 {
20259  triface searchtet, neightet, spintet;
20260  face searchsh, neighsh, neineish, *parysh;
20261  face bdsegs[3];
20262  point startpt, endpt, apexpt, *parypt;
20263  point steinerpt;
20264  insertvertexflags ivf;
20265  int success;
20266  int t1ver;
20267  int i, j;
20268 
20269  if (b->verbose > 1) {
20270  printf(" Recover subfaces [%s level = %2d] #: %ld.\n",
20271  (b->fliplinklevel > 0) ? "fixed" : "auto",
20272  (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
20273  subfacstack->objects);
20274  }
20275 
20276  // Loop until 'subfacstack' is empty.
20277  while (subfacstack->objects > 0l) {
20278 
20279  subfacstack->objects--;
20280  parysh = (face *) fastlookup(subfacstack, subfacstack->objects);
20281  searchsh = *parysh;
20282 
20283  if (searchsh.sh[3] == NULL) continue; // Skip a dead subface.
20284 
20285  stpivot(searchsh, neightet);
20286  if (neightet.tet != NULL) continue; // Skip a recovered subface.
20287 
20288 
20289  if (b->verbose > 2) {
20290  printf(" Recover subface (%d, %d, %d).\n",pointmark(sorg(searchsh)),
20291  pointmark(sdest(searchsh)), pointmark(sapex(searchsh)));
20292  }
20293 
20294  // The three edges of the face need to be existed first.
20295  for (i = 0; i < 3; i++) {
20296  sspivot(searchsh, bdsegs[i]);
20297  if (bdsegs[i].sh != NULL) {
20298  // The segment must exist.
20299  sstpivot1(bdsegs[i], searchtet);
20300  if (searchtet.tet == NULL) {
20301  terminatetetgen(this, 2);
20302  }
20303  } else {
20304  // This edge is not a segment (due to a Steiner point).
20305  // Check whether it exists or not.
20306  success = 0;
20307  startpt = sorg(searchsh);
20308  endpt = sdest(searchsh);
20309  point2tetorg(startpt, searchtet);
20310  finddirection(&searchtet, endpt);
20311  if (dest(searchtet) == endpt) {
20312  success = 1;
20313  } else {
20314  // The edge is missing. Try to recover it.
20315  if (recoveredgebyflips(startpt, endpt, &searchsh, &searchtet, 0)) {
20316  success = 1;
20317  } else {
20318  if (recoveredgebyflips(endpt, startpt, &searchsh, &searchtet, 0)) {
20319  success = 1;
20320  }
20321  }
20322  }
20323  if (success) {
20324  // Insert a temporary segment to protect this edge.
20325  makeshellface(subsegs, &(bdsegs[i]));
20326  setshvertices(bdsegs[i], startpt, endpt, NULL);
20327  smarktest2(bdsegs[i]); // It's a temporary segment.
20328  // Insert this segment into surface mesh.
20329  ssbond(searchsh, bdsegs[i]);
20330  spivot(searchsh, neighsh);
20331  if (neighsh.sh != NULL) {
20332  ssbond(neighsh, bdsegs[i]);
20333  }
20334  // Insert this segment into tetrahedralization.
20335  sstbond1(bdsegs[i], searchtet);
20336  // Bond the segment to all tets containing it.
20337  spintet = searchtet;
20338  do {
20339  tssbond1(spintet, bdsegs[i]);
20340  fnextself(spintet);
20341  } while (spintet.tet != searchtet.tet);
20342  } else {
20343  // An edge of this subface is missing. Can't recover this subface.
20344  // Delete any temporary segment that has been created.
20345  for (j = (i - 1); j >= 0; j--) {
20346  if (smarktest2ed(bdsegs[j])) {
20347  spivot(bdsegs[j], neineish);
20348  ssdissolve(neineish);
20349  spivot(neineish, neighsh);
20350  if (neighsh.sh != NULL) {
20351  ssdissolve(neighsh);
20352  }
20353  sstpivot1(bdsegs[j], searchtet);
20354  spintet = searchtet;
20355  while (1) {
20356  tssdissolve1(spintet);
20357  fnextself(spintet);
20358  if (spintet.tet == searchtet.tet) break;
20359  }
20360  shellfacedealloc(subsegs, bdsegs[j].sh);
20361  }
20362  } // j
20363  if (steinerflag) {
20364  // Add a Steiner point at the midpoint of this edge.
20365  if (b->verbose > 2) {
20366  printf(" Add a Steiner point in subedge (%d, %d).\n",
20367  pointmark(startpt), pointmark(endpt));
20368  }
20369  makepoint(&steinerpt, FREEFACETVERTEX);
20370  for (j = 0; j < 3; j++) {
20371  steinerpt[j] = 0.5 * (startpt[j] + endpt[j]);
20372  }
20373 
20374  point2tetorg(startpt, searchtet); // Start from 'searchtet'.
20375  ivf.iloc = (int) OUTSIDE; // Need point location.
20376  ivf.bowywat = 1;
20377  ivf.lawson = 0;
20378  ivf.rejflag = 0;
20379  ivf.chkencflag = 0;
20380  ivf.sloc = (int) ONEDGE;
20381  ivf.sbowywat = 1; // Allow flips in facet.
20382  ivf.splitbdflag = 0;
20383  ivf.validflag = 1;
20384  ivf.respectbdflag = 1;
20385  ivf.assignmeshsize = b->metric;
20386  if (!insertpoint(steinerpt, &searchtet, &searchsh, NULL, &ivf)) {
20387  terminatetetgen(this, 2);
20388  }
20389  // Save this Steiner point (for removal).
20390  // Re-use the array 'subvertstack'.
20391  subvertstack->newindex((void **) &parypt);
20392  *parypt = steinerpt;
20393 
20394  st_facref_count++;
20395  if (steinerleft > 0) steinerleft--;
20396  } // if (steinerflag)
20397  break;
20398  }
20399  }
20400  senextself(searchsh);
20401  } // i
20402 
20403  if (i == 3) {
20404  // Recover the subface.
20405  startpt = sorg(searchsh);
20406  endpt = sdest(searchsh);
20407  apexpt = sapex(searchsh);
20408 
20409  success = recoverfacebyflips(startpt,endpt,apexpt,&searchsh,&searchtet);
20410 
20411  // Delete any temporary segment that has been created.
20412  for (j = 0; j < 3; j++) {
20413  if (smarktest2ed(bdsegs[j])) {
20414  spivot(bdsegs[j], neineish);
20415  ssdissolve(neineish);
20416  spivot(neineish, neighsh);
20417  if (neighsh.sh != NULL) {
20418  ssdissolve(neighsh);
20419  }
20420  sstpivot1(bdsegs[j], neightet);
20421  spintet = neightet;
20422  while (1) {
20423  tssdissolve1(spintet);
20424  fnextself(spintet);
20425  if (spintet.tet == neightet.tet) break;
20426  }
20427  shellfacedealloc(subsegs, bdsegs[j].sh);
20428  }
20429  } // j
20430 
20431  if (success) {
20432  if (searchsh.sh != NULL) {
20433  // Face is recovered. Insert it.
20434  tsbond(searchtet, searchsh);
20435  fsymself(searchtet);
20436  sesymself(searchsh);
20437  tsbond(searchtet, searchsh);
20438  }
20439  } else {
20440  if (steinerflag) {
20441  // Add a Steiner point at the barycenter of this subface.
20442  if (b->verbose > 2) {
20443  printf(" Add a Steiner point in subface (%d, %d, %d).\n",
20444  pointmark(startpt), pointmark(endpt), pointmark(apexpt));
20445  }
20446  makepoint(&steinerpt, FREEFACETVERTEX);
20447  for (j = 0; j < 3; j++) {
20448  steinerpt[j] = (startpt[j] + endpt[j] + apexpt[j]) / 3.0;
20449  }
20450 
20451  point2tetorg(startpt, searchtet); // Start from 'searchtet'.
20452  ivf.iloc = (int) OUTSIDE; // Need point location.
20453  ivf.bowywat = 1;
20454  ivf.lawson = 0;
20455  ivf.rejflag = 0;
20456  ivf.chkencflag = 0;
20457  ivf.sloc = (int) ONFACE;
20458  ivf.sbowywat = 1; // Allow flips in facet.
20459  ivf.splitbdflag = 0;
20460  ivf.validflag = 1;
20461  ivf.respectbdflag = 1;
20462  ivf.assignmeshsize = b->metric;
20463  if (!insertpoint(steinerpt, &searchtet, &searchsh, NULL, &ivf)) {
20464  terminatetetgen(this, 2);
20465  }
20466  // Save this Steiner point (for removal).
20467  // Re-use the array 'subvertstack'.
20468  subvertstack->newindex((void **) &parypt);
20469  *parypt = steinerpt;
20470 
20471  st_facref_count++;
20472  if (steinerleft > 0) steinerleft--;
20473  } // if (steinerflag)
20474  }
20475  } else {
20476  success = 0;
20477  }
20478 
20479  if (!success) {
20480  if (misshlist != NULL) {
20481  // Save this subface.
20482  misshlist->newindex((void **) &parysh);
20483  *parysh = searchsh;
20484  }
20485  }
20486 
20487  } // while (subfacstack->objects > 0l)
20488 
20489  return 0;
20490 }
20491 
20493 // //
20494 // getvertexstar() Return the star of a vertex. //
20495 // //
20496 // If the flag 'fullstar' is set, return the complete star of this vertex. //
20497 // Otherwise, only a part of the star which is bounded by facets is returned.//
20498 // //
20499 // 'tetlist' returns the list of tets in the star of the vertex 'searchpt'. //
20500 // Every tet in 'tetlist' is at the face opposing to 'searchpt'. //
20501 // //
20502 // 'vertlist' returns the list of vertices in the star (exclude 'searchpt'). //
20503 // //
20504 // 'shlist' returns the list of subfaces in the star. Each subface must face //
20505 // to the interior of this star. //
20506 // //
20508 
20509 int tetgenmesh::getvertexstar(int fullstar, point searchpt, arraypool* tetlist,
20510  arraypool* vertlist, arraypool* shlist)
20511 {
20512  triface searchtet, neightet, *parytet;
20513  face checksh, *parysh;
20514  point pt, *parypt;
20515  int collectflag;
20516  int t1ver;
20517  int i, j;
20518 
20519  point2tetorg(searchpt, searchtet);
20520 
20521  // Go to the opposite face (the link face) of the vertex.
20522  enextesymself(searchtet);
20523  //assert(oppo(searchtet) == searchpt);
20524  infect(searchtet); // Collect this tet (link face).
20525  tetlist->newindex((void **) &parytet);
20526  *parytet = searchtet;
20527  if (vertlist != NULL) {
20528  // Collect three (link) vertices.
20529  j = (searchtet.ver & 3); // The current vertex index.
20530  for (i = 1; i < 4; i++) {
20531  pt = (point) searchtet.tet[4 + ((j + i) % 4)];
20532  pinfect(pt);
20533  vertlist->newindex((void **) &parypt);
20534  *parypt = pt;
20535  }
20536  }
20537 
20538  collectflag = 1;
20539  esym(searchtet, neightet);
20540  if (issubface(neightet)) {
20541  if (shlist != NULL) {
20542  tspivot(neightet, checksh);
20543  if (!sinfected(checksh)) {
20544  // Collect this subface (link edge).
20545  sinfected(checksh);
20546  shlist->newindex((void **) &parysh);
20547  *parysh = checksh;
20548  }
20549  }
20550  if (!fullstar) {
20551  collectflag = 0;
20552  }
20553  }
20554  if (collectflag) {
20555  fsymself(neightet); // Goto the adj tet of this face.
20556  esymself(neightet); // Goto the oppo face of this vertex.
20557  // assert(oppo(neightet) == searchpt);
20558  infect(neightet); // Collect this tet (link face).
20559  tetlist->newindex((void **) &parytet);
20560  *parytet = neightet;
20561  if (vertlist != NULL) {
20562  // Collect its apex.
20563  pt = apex(neightet);
20564  pinfect(pt);
20565  vertlist->newindex((void **) &parypt);
20566  *parypt = pt;
20567  }
20568  } // if (collectflag)
20569 
20570  // Continue to collect all tets in the star.
20571  for (i = 0; i < tetlist->objects; i++) {
20572  searchtet = * (triface *) fastlookup(tetlist, i);
20573  // Note that 'searchtet' is a face opposite to 'searchpt', and the neighbor
20574  // tet at the current edge is already collected.
20575  // Check the neighbors at the other two edges of this face.
20576  for (j = 0; j < 2; j++) {
20577  collectflag = 1;
20578  enextself(searchtet);
20579  esym(searchtet, neightet);
20580  if (issubface(neightet)) {
20581  if (shlist != NULL) {
20582  tspivot(neightet, checksh);
20583  if (!sinfected(checksh)) {
20584  // Collect this subface (link edge).
20585  sinfected(checksh);
20586  shlist->newindex((void **) &parysh);
20587  *parysh = checksh;
20588  }
20589  }
20590  if (!fullstar) {
20591  collectflag = 0;
20592  }
20593  }
20594  if (collectflag) {
20595  fsymself(neightet);
20596  if (!infected(neightet)) {
20597  esymself(neightet); // Go to the face opposite to 'searchpt'.
20598  infect(neightet);
20599  tetlist->newindex((void **) &parytet);
20600  *parytet = neightet;
20601  if (vertlist != NULL) {
20602  // Check if a vertex is collected.
20603  pt = apex(neightet);
20604  if (!pinfected(pt)) {
20605  pinfect(pt);
20606  vertlist->newindex((void **) &parypt);
20607  *parypt = pt;
20608  }
20609  }
20610  } // if (!infected(neightet))
20611  } // if (collectflag)
20612  } // j
20613  } // i
20614 
20615 
20616  // Uninfect the list of tets and vertices.
20617  for (i = 0; i < tetlist->objects; i++) {
20618  parytet = (triface *) fastlookup(tetlist, i);
20619  uninfect(*parytet);
20620  }
20621 
20622  if (vertlist != NULL) {
20623  for (i = 0; i < vertlist->objects; i++) {
20624  parypt = (point *) fastlookup(vertlist, i);
20625  puninfect(*parypt);
20626  }
20627  }
20628 
20629  if (shlist != NULL) {
20630  for (i = 0; i < shlist->objects; i++) {
20631  parysh = (face *) fastlookup(shlist, i);
20632  suninfect(*parysh);
20633  }
20634  }
20635 
20636  return (int) tetlist->objects;
20637 }
20638 
20640 // //
20641 // getedge() Get a tetrahedron having the two endpoints. //
20642 // //
20643 // The method here is to search the second vertex in the link faces of the //
20644 // first vertex. The global array 'cavetetlist' is re-used for searching. //
20645 // //
20646 // This function is used for the case when the mesh is non-convex. Otherwise,//
20647 // the function finddirection() should be faster than this. //
20648 // //
20650 
20651 int tetgenmesh::getedge(point e1, point e2, triface *tedge)
20652 {
20653  triface searchtet, neightet, *parytet;
20654  point pt;
20655  int done;
20656  int i, j;
20657 
20658  if (b->verbose > 2) {
20659  printf(" Get edge from %d to %d.\n", pointmark(e1), pointmark(e2));
20660  }
20661 
20662  // Quickly check if 'tedge' is just this edge.
20663  if (!isdeadtet(*tedge)) {
20664  if (org(*tedge) == e1) {
20665  if (dest(*tedge) == e2) {
20666  return 1;
20667  }
20668  } else if (org(*tedge) == e2) {
20669  if (dest(*tedge) == e1) {
20670  esymself(*tedge);
20671  return 1;
20672  }
20673  }
20674  }
20675 
20676  // Search for the edge [e1, e2].
20677  point2tetorg(e1, *tedge);
20678  finddirection(tedge, e2);
20679  if (dest(*tedge) == e2) {
20680  return 1;
20681  } else {
20682  // Search for the edge [e2, e1].
20683  point2tetorg(e2, *tedge);
20684  finddirection(tedge, e1);
20685  if (dest(*tedge) == e1) {
20686  esymself(*tedge);
20687  return 1;
20688  }
20689  }
20690 
20691 
20692  // Go to the link face of e1.
20693  point2tetorg(e1, searchtet);
20694  enextesymself(searchtet);
20695  arraypool *tetlist = cavebdrylist;
20696 
20697  // Search e2.
20698  for (i = 0; i < 3; i++) {
20699  pt = apex(searchtet);
20700  if (pt == e2) {
20701  // Found. 'searchtet' is [#,#,e2,e1].
20702  eorgoppo(searchtet, *tedge); // [e1,e2,#,#].
20703  return 1;
20704  }
20705  enextself(searchtet);
20706  }
20707 
20708  // Get the adjacent link face at 'searchtet'.
20709  fnext(searchtet, neightet);
20710  esymself(neightet);
20711  // assert(oppo(neightet) == e1);
20712  pt = apex(neightet);
20713  if (pt == e2) {
20714  // Found. 'neightet' is [#,#,e2,e1].
20715  eorgoppo(neightet, *tedge); // [e1,e2,#,#].
20716  return 1;
20717  }
20718 
20719  // Continue searching in the link face of e1.
20720  infect(searchtet);
20721  tetlist->newindex((void **) &parytet);
20722  *parytet = searchtet;
20723  infect(neightet);
20724  tetlist->newindex((void **) &parytet);
20725  *parytet = neightet;
20726 
20727  done = 0;
20728 
20729  for (i = 0; (i < tetlist->objects) && !done; i++) {
20730  parytet = (triface *) fastlookup(tetlist, i);
20731  searchtet = *parytet;
20732  for (j = 0; (j < 2) && !done; j++) {
20733  enextself(searchtet);
20734  fnext(searchtet, neightet);
20735  if (!infected(neightet)) {
20736  esymself(neightet);
20737  pt = apex(neightet);
20738  if (pt == e2) {
20739  // Found. 'neightet' is [#,#,e2,e1].
20740  eorgoppo(neightet, *tedge);
20741  done = 1;
20742  } else {
20743  infect(neightet);
20744  tetlist->newindex((void **) &parytet);
20745  *parytet = neightet;
20746  }
20747  }
20748  } // j
20749  } // i
20750 
20751  // Uninfect the list of visited tets.
20752  for (i = 0; i < tetlist->objects; i++) {
20753  parytet = (triface *) fastlookup(tetlist, i);
20754  uninfect(*parytet);
20755  }
20756  tetlist->restart();
20757 
20758  return done;
20759 }
20760 
20762 // //
20763 // reduceedgesatvertex() Reduce the number of edges at a given vertex. //
20764 // //
20765 // 'endptlist' contains the endpoints of edges connecting at the vertex. //
20766 // //
20768 
20769 int tetgenmesh::reduceedgesatvertex(point startpt, arraypool* endptlist)
20770 {
20771  triface searchtet;
20772  point *pendpt, *parypt;
20773  enum interresult dir;
20774  flipconstraints fc;
20775  int reduceflag;
20776  int count;
20777  int n, i, j;
20778 
20779 
20780  fc.remvert = startpt;
20781  fc.checkflipeligibility = 1;
20782 
20783  while (1) {
20784 
20785  count = 0;
20786 
20787  for (i = 0; i < endptlist->objects; i++) {
20788  pendpt = (point *) fastlookup(endptlist, i);
20789  if (*pendpt == dummypoint) {
20790  continue; // Do not reduce a virtual edge.
20791  }
20792  reduceflag = 0;
20793  // Find the edge.
20794  if (nonconvex) {
20795  if (getedge(startpt, *pendpt, &searchtet)) {
20796  dir = ACROSSVERT;
20797  } else {
20798  // The edge does not exist (was flipped).
20799  dir = INTERSECT;
20800  }
20801  } else {
20802  point2tetorg(startpt, searchtet);
20803  dir = finddirection(&searchtet, *pendpt);
20804  }
20805  if (dir == ACROSSVERT) {
20806  if (dest(searchtet) == *pendpt) {
20807  // Do not flip a segment.
20808  if (!issubseg(searchtet)) {
20809  n = removeedgebyflips(&searchtet, &fc);
20810  if (n == 2) {
20811  reduceflag = 1;
20812  }
20813  }
20814  }
20815  } else {
20816  // The edge has been flipped.
20817  reduceflag = 1;
20818  }
20819  if (reduceflag) {
20820  count++;
20821  // Move the last vertex into this slot.
20822  j = endptlist->objects - 1;
20823  parypt = (point *) fastlookup(endptlist, j);
20824  *pendpt = *parypt;
20825  endptlist->objects--;
20826  i--;
20827  }
20828  } // i
20829 
20830  if (count == 0) {
20831  // No edge is reduced.
20832  break;
20833  }
20834 
20835  } // while (1)
20836 
20837  return (int) endptlist->objects;
20838 }
20839 
20841 // //
20842 // removevertexbyflips() Remove a vertex by flips. //
20843 // //
20844 // This routine attempts to remove the given vertex 'rempt' (p) from the //
20845 // tetrahedralization (T) by a sequence of flips. //
20846 // //
20847 // The algorithm used here is a simple edge reduce method. Suppose there are //
20848 // n edges connected at p. We try to reduce the number of edges by flipping //
20849 // any edge (not a segment) that is connecting at p. //
20850 // //
20851 // Unless T is a Delaunay tetrahedralization, there is no guarantee that 'p' //
20852 // can be successfully removed. //
20853 // //
20855 
20856 int tetgenmesh::removevertexbyflips(point steinerpt)
20857 {
20858  triface *fliptets = NULL, wrktets[4];
20859  triface searchtet, spintet, neightet;
20860  face parentsh, spinsh, checksh;
20861  face leftseg, rightseg, checkseg;
20862  point lpt = NULL, rpt = NULL, apexpt; //, *parypt;
20863  flipconstraints fc;
20864  enum verttype vt;
20865  enum locateresult loc;
20866  int valence, removeflag;
20867  int slawson;
20868  int t1ver;
20869  int n, i;
20870 
20871  vt = pointtype(steinerpt);
20872 
20873 
20874  if (vt == FREESEGVERTEX) {
20875  sdecode(point2sh(steinerpt), leftseg);
20876  leftseg.shver = 0;
20877  if (sdest(leftseg) == steinerpt) {
20878  senext(leftseg, rightseg);
20879  spivotself(rightseg);
20880  rightseg.shver = 0;
20881  } else {
20882  rightseg = leftseg;
20883  senext2(rightseg, leftseg);
20884  spivotself(leftseg);
20885  leftseg.shver = 0;
20886  }
20887  lpt = sorg(leftseg);
20888  rpt = sdest(rightseg);
20889  if (b->verbose > 2) {
20890  printf(" Removing Steiner point %d in segment (%d, %d).\n",
20891  pointmark(steinerpt), pointmark(lpt), pointmark(rpt));
20892 
20893  }
20894  } else if (vt == FREEFACETVERTEX) {
20895  if (b->verbose > 2) {
20896  printf(" Removing Steiner point %d in facet.\n",
20897  pointmark(steinerpt));
20898  }
20899  } else if (vt == FREEVOLVERTEX) {
20900  if (b->verbose > 2) {
20901  printf(" Removing Steiner point %d in volume.\n",
20902  pointmark(steinerpt));
20903  }
20904  } else if (vt == VOLVERTEX) {
20905  if (b->verbose > 2) {
20906  printf(" Removing a point %d in volume.\n",
20907  pointmark(steinerpt));
20908  }
20909  } else {
20910  // It is not a Steiner point.
20911  return 0;
20912  }
20913 
20914  // Try to reduce the number of edges at 'p' by flips.
20915  getvertexstar(1, steinerpt, cavetetlist, cavetetvertlist, NULL);
20916  cavetetlist->restart(); // This list may be re-used.
20917  if (cavetetvertlist->objects > 3l) {
20918  valence = reduceedgesatvertex(steinerpt, cavetetvertlist);
20919  } else {
20920  valence = cavetetvertlist->objects;
20921  }
20922  cavetetvertlist->restart();
20923 
20924  removeflag = 0;
20925 
20926  if (valence == 4) {
20927  // Only 4 vertices (4 tets) left! 'p' is inside the convex hull of the 4
20928  // vertices. This case is due to that 'p' is not exactly on the segment.
20929  point2tetorg(steinerpt, searchtet);
20930  loc = INTETRAHEDRON;
20931  removeflag = 1;
20932  } else if (valence == 5) {
20933  // There are 5 edges.
20934  if (vt == FREESEGVERTEX) {
20935  sstpivot1(leftseg, searchtet);
20936  if (org(searchtet) != steinerpt) {
20937  esymself(searchtet);
20938  }
20939  i = 0; // Count the numbe of tet at the edge [p,lpt].
20940  neightet.tet = NULL; // Init the face.
20941  spintet = searchtet;
20942  while (1) {
20943  i++;
20944  if (apex(spintet) == rpt) {
20945  // Remember the face containing the edge [lpt, rpt].
20946  neightet = spintet;
20947  }
20948  fnextself(spintet);
20949  if (spintet.tet == searchtet.tet) break;
20950  }
20951  if (i == 3) {
20952  // This case has been checked below.
20953  } else if (i == 4) {
20954  // There are 4 tets sharing at [p,lpt]. There must be 4 tets sharing
20955  // at [p,rpt]. There must be a face [p, lpt, rpt].
20956  if (apex(neightet) == rpt) {
20957  // The edge (segment) has been already recovered!
20958  // Check if a 6-to-2 flip is possible (to remove 'p').
20959  // Let 'searchtet' be [p,d,a,b]
20960  esym(neightet, searchtet);
20961  enextself(searchtet);
20962  // Check if there are exactly three tets at edge [p,d].
20963  wrktets[0] = searchtet; // [p,d,a,b]
20964  for (i = 0; i < 2; i++) {
20965  fnext(wrktets[i], wrktets[i+1]); // [p,d,b,c], [p,d,c,a]
20966  }
20967  if (apex(wrktets[0]) == oppo(wrktets[2])) {
20968  loc = ONFACE;
20969  removeflag = 1;
20970  }
20971  }
20972  }
20973  } else if (vt == FREEFACETVERTEX) {
20974  // It is possible to do a 6-to-2 flip to remove the vertex.
20975  point2tetorg(steinerpt, searchtet);
20976  // Get the three faces of 'searchtet' which share at p.
20977  // All faces has p as origin.
20978  wrktets[0] = searchtet;
20979  wrktets[1] = searchtet;
20980  esymself(wrktets[1]);
20981  enextself(wrktets[1]);
20982  wrktets[2] = searchtet;
20983  eprevself(wrktets[2]);
20984  esymself(wrktets[2]);
20985  // All internal edges of the six tets have valance either 3 or 4.
20986  // Get one edge which has valance 3.
20987  searchtet.tet = NULL;
20988  for (i = 0; i < 3; i++) {
20989  spintet = wrktets[i];
20990  valence = 0;
20991  while (1) {
20992  valence++;
20993  fnextself(spintet);
20994  if (spintet.tet == wrktets[i].tet) break;
20995  }
20996  if (valence == 3) {
20997  // Found the edge.
20998  searchtet = wrktets[i];
20999  break;
21000  }
21001  }
21002  // Note, we do not detach the three subfaces at p.
21003  // They will be removed within a 4-to-1 flip.
21004  loc = ONFACE;
21005  removeflag = 1;
21006  }
21007  //removeflag = 1;
21008  }
21009 
21010  if (!removeflag) {
21011  if (vt == FREESEGVERTEX) {
21012  // Check is it possible to recover the edge [lpt,rpt].
21013  // The condition to check is: Whether each tet containing 'leftseg' is
21014  // adjacent to a tet containing 'rightseg'.
21015  sstpivot1(leftseg, searchtet);
21016  if (org(searchtet) != steinerpt) {
21017  esymself(searchtet);
21018  }
21019  spintet = searchtet;
21020  while (1) {
21021  // Go to the bottom face of this tet.
21022  eprev(spintet, neightet);
21023  esymself(neightet); // [steinerpt, p1, p2, lpt]
21024  // Get the adjacent tet.
21025  fsymself(neightet); // [p1, steinerpt, p2, rpt]
21026  if (oppo(neightet) != rpt) {
21027  // Found a non-matching adjacent tet.
21028  break;
21029  }
21030  {
21031  // [2017-10-15] Check if the tet is inverted?
21032  point chkp1 = org(neightet);
21033  point chkp2 = apex(neightet);
21034  REAL chkori = orient3d(rpt, lpt, chkp1, chkp2);
21035  if (chkori >= 0.0) {
21036  // Either inverted or degenerated.
21037  break;
21038  }
21039  }
21040  fnextself(spintet);
21041  if (spintet.tet == searchtet.tet) {
21042  // 'searchtet' is [p,d,p1,p2].
21043  loc = ONEDGE;
21044  removeflag = 1;
21045  break;
21046  }
21047  }
21048  } // if (vt == FREESEGVERTEX)
21049  }
21050 
21051  if (!removeflag) {
21052  if (vt == FREESEGVERTEX) {
21053  // Check if the edge [lpt, rpt] exists.
21054  if (getedge(lpt, rpt, &searchtet)) {
21055  // We have recovered this edge. Shift the vertex into the volume.
21056  // We can recover this edge if the subfaces are not recovered yet.
21057  if (!checksubfaceflag) {
21058  // Remove the vertex from the surface mesh.
21059  // This will re-create the segment [lpt, rpt] and re-triangulate
21060  // all the facets at the segment.
21061  // Detach the subsegments from their surrounding tets.
21062  for (i = 0; i < 2; i++) {
21063  checkseg = (i == 0) ? leftseg : rightseg;
21064  sstpivot1(checkseg, neightet);
21065  spintet = neightet;
21066  while (1) {
21067  tssdissolve1(spintet);
21068  fnextself(spintet);
21069  if (spintet.tet == neightet.tet) break;
21070  }
21071  sstdissolve1(checkseg);
21072  } // i
21073  slawson = 1; // Do lawson flip after removal.
21074  spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
21075  sremovevertex(steinerpt, &parentsh, &rightseg, slawson);
21076  // Clear the list for new subfaces.
21077  caveshbdlist->restart();
21078  // Insert the new segment.
21079  sstbond1(rightseg, searchtet);
21080  spintet = searchtet;
21081  while (1) {
21082  tssbond1(spintet, rightseg);
21083  fnextself(spintet);
21084  if (spintet.tet == searchtet.tet) break;
21085  }
21086  // The Steiner point has been shifted into the volume.
21087  setpointtype(steinerpt, FREEVOLVERTEX);
21088  st_segref_count--;
21089  st_volref_count++;
21090  return 1;
21091  } // if (!checksubfaceflag)
21092  } // if (getedge(...))
21093  } // if (vt == FREESEGVERTEX)
21094  } // if (!removeflag)
21095 
21096  if (!removeflag) {
21097  return 0;
21098  }
21099 
21100  if (vt == FREESEGVERTEX) {
21101  // Detach the subsegments from their surronding tets.
21102  for (i = 0; i < 2; i++) {
21103  checkseg = (i == 0) ? leftseg : rightseg;
21104  sstpivot1(checkseg, neightet);
21105  spintet = neightet;
21106  while (1) {
21107  tssdissolve1(spintet);
21108  fnextself(spintet);
21109  if (spintet.tet == neightet.tet) break;
21110  }
21111  sstdissolve1(checkseg);
21112  } // i
21113  if (checksubfaceflag) {
21114  // Detach the subfaces at the subsegments from their attached tets.
21115  for (i = 0; i < 2; i++) {
21116  checkseg = (i == 0) ? leftseg : rightseg;
21117  spivot(checkseg, parentsh);
21118  if (parentsh.sh != NULL) {
21119  spinsh = parentsh;
21120  while (1) {
21121  stpivot(spinsh, neightet);
21122  if (neightet.tet != NULL) {
21123  tsdissolve(neightet);
21124  }
21125  sesymself(spinsh);
21126  stpivot(spinsh, neightet);
21127  if (neightet.tet != NULL) {
21128  tsdissolve(neightet);
21129  }
21130  stdissolve(spinsh);
21131  spivotself(spinsh); // Go to the next subface.
21132  if (spinsh.sh == parentsh.sh) break;
21133  }
21134  }
21135  } // i
21136  } // if (checksubfaceflag)
21137  }
21138 
21139  if (loc == INTETRAHEDRON) {
21140  // Collect the four tets containing 'p'.
21141  fliptets = new triface[4];
21142  fliptets[0] = searchtet; // [p,d,a,b]
21143  for (i = 0; i < 2; i++) {
21144  fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a]
21145  }
21146  eprev(fliptets[0], fliptets[3]);
21147  fnextself(fliptets[3]); // it is [a,p,b,c]
21148  eprevself(fliptets[3]);
21149  esymself(fliptets[3]); // [a,b,c,p].
21150  // Remove p by a 4-to-1 flip.
21151  //flip41(fliptets, 1, 0, 0);
21152  /*
21153  { // Do not flip if there are wrong number of subfaces inside.
21154  // Check if there are three subfaces at 'p'.
21155  triface newface; face flipshs[3];
21156  int spivot = 0, scount = 0;
21157  for (i = 0; i < 3; i++) {
21158  fnext(fliptets[3], newface); // [a,b,p,d],[b,c,p,d],[c,a,p,d].
21159  tspivot(newface, flipshs[i]);
21160  if (flipshs[i].sh != NULL) {
21161  spivot = i; // Remember this subface.
21162  scount++;
21163  }
21164  enextself(fliptets[3]);
21165  }
21166  if (scount > 0) {
21167  // There are three subfaces connecting at p.
21168  // Only do flip if a 3-to-1 flip is possible at p at the bottom face.
21169  if (scount != 3) {
21170  // Wrong number of subfaces. Do not flip.
21171  delete [] fliptets;
21172  return 0;
21173  }
21174  // [2018-03-07] an old fix, not 100% safe.
21175  // if (scount < 3) {
21176  // // The new subface is one of {[a,b,d], [b,c,d], [c,a,d]}.
21177  // // assert(scount == 1); // spivot >= 0
21178  // if (scount != 1) {
21179  // // Wrong number of subfaces. Do not flip.
21180  // delete [] fliptets;
21181  // return 0;
21182  // }
21183  //}
21184  }
21185  }
21186  */
21187  if (vt == FREEFACETVERTEX) {
21188  // [2018-03-08] Check if the last 4-to-1 flip is valid.
21189  // fliptets[0],[1],[2] are [p,d,a,b],[p,d,b,c],[p,d,c,a]
21190  triface checktet, chkface;
21191  for (i = 0; i < 3; i++) {
21192  enext(fliptets[i], checktet);
21193  esymself(checktet); // [a,d,b,p],[b,d,c,p],[c,d,a,p]
21194  int scount = 0; int k;
21195  for (k = 0; k < 3; k++) {
21196  esym(checktet, chkface);
21197  if (issubface(chkface)) scount++;
21198  enextself(checktet);
21199  }
21200  if (scount == 3) {
21201  break; // Found a tet which support a 3-to-1 flip.
21202  } else if (scount == 2) {
21203  // This is a strange configuration. Debug it.
21204  // Do not do this flip.
21205  delete [] fliptets;
21206  return 0;
21207  }
21208  }
21209  if (i == 3) {
21210  // No tet in [p,d,a,b],[p,d,b,c],[p,d,c,a] support it.
21211  int scount = 0;
21212  for (i = 0; i < 3; i++) {
21213  eprev(fliptets[i], checktet);
21214  esymself(checktet); // [p,a,b,d],[p,b,c,d],[p,c,a,d]
21215  if (issubface(chkface)) scount++;
21216  }
21217  if (scount != 3) {
21218  // Do not do this flip.
21219  delete [] fliptets;
21220  return 0;
21221  }
21222  }
21223  } // if (vt == FREEFACETVERTEX)
21224  flip41(fliptets, 1, &fc);
21225  //recenttet = fliptets[0];
21226  } else if (loc == ONFACE) {
21227  // Let the original two tets be [a,b,c,d] and [b,a,c,e]. And p is in
21228  // face [a,b,c]. Let 'searchtet' be the tet [p,d,a,b].
21229  // Collect the six tets containing 'p'.
21230  fliptets = new triface[6];
21231  fliptets[0] = searchtet; // [p,d,a,b]
21232  for (i = 0; i < 2; i++) {
21233  fnext(fliptets[i], fliptets[i+1]); // [p,d,b,c], [p,d,c,a]
21234  }
21235  eprev(fliptets[0], fliptets[3]);
21236  fnextself(fliptets[3]); // [a,p,b,e]
21237  esymself(fliptets[3]); // [p,a,e,b]
21238  eprevself(fliptets[3]); // [e,p,a,b]
21239  for (i = 3; i < 5; i++) {
21240  fnext(fliptets[i], fliptets[i+1]); // [e,p,b,c], [e,p,c,a]
21241  }
21242  if (vt == FREEFACETVERTEX) {
21243  // We need to determine the location of three subfaces at p.
21244  valence = 0; // Re-use it.
21245  for (i = 3; i < 6; i++) {
21246  if (issubface(fliptets[i])) valence++;
21247  }
21248  if (valence > 0) {
21249  // We must do 3-to-2 flip in the upper part. We simply re-arrange
21250  // the six tets.
21251  for (i = 0; i < 3; i++) {
21252  esym(fliptets[i+3], wrktets[i]);
21253  esym(fliptets[i], fliptets[i+3]);
21254  fliptets[i] = wrktets[i];
21255  }
21256  // Swap the last two pairs, i.e., [1]<->[[2], and [4]<->[5]
21257  wrktets[1] = fliptets[1];
21258  fliptets[1] = fliptets[2];
21259  fliptets[2] = wrktets[1];
21260  wrktets[1] = fliptets[4];
21261  fliptets[4] = fliptets[5];
21262  fliptets[5] = wrktets[1];
21263  }
21264  // [2018-03-08] Check if the last 4-to-1 flip is valid.
21265  // fliptets[0],[1],[2] are [p,d,a,b],[p,d,b,c],[p,d,c,a]
21266  triface checktet, chkface;
21267  for (i = 0; i < 3; i++) {
21268  enext(fliptets[i], checktet);
21269  esymself(checktet); // [a,d,b,p],[b,d,c,p],[c,d,a,p]
21270  int scount = 0; int k;
21271  for (k = 0; k < 3; k++) {
21272  esym(checktet, chkface);
21273  if (issubface(chkface)) scount++;
21274  enextself(checktet);
21275  }
21276  if (scount == 3) {
21277  break; // Found a tet which support a 3-to-1 flip.
21278  } else if (scount == 2) {
21279  // This is a strange configuration. Debug it.
21280  // Do not do this flip.
21281  delete [] fliptets;
21282  return 0;
21283  }
21284  }
21285  if (i == 3) {
21286  // No tet in [p,d,a,b],[p,d,b,c],[p,d,c,a] support it.
21287  int scount = 0;
21288  for (i = 0; i < 3; i++) {
21289  eprev(fliptets[i], checktet);
21290  esymself(checktet); // [p,a,b,d],[p,b,c,d],[p,c,a,d]
21291  if (issubface(chkface)) scount++;
21292  }
21293  if (scount != 3) {
21294  // Do not do this flip.
21295  delete [] fliptets;
21296  return 0;
21297  }
21298  }
21299  } // vt == FREEFACETVERTEX
21300  // Remove p by a 6-to-2 flip, which is a combination of two flips:
21301  // a 3-to-2 (deletes the edge [e,p]), and
21302  // a 4-to-1 (deletes the vertex p).
21303  // First do a 3-to-2 flip on [e,p,a,b],[e,p,b,c],[e,p,c,a]. It creates
21304  // two new tets: [a,b,c,p] and [b,a,c,e]. The new tet [a,b,c,p] is
21305  // degenerate (has zero volume). It will be deleted in the followed
21306  // 4-to-1 flip.
21307  //flip32(&(fliptets[3]), 1, 0, 0);
21308  flip32(&(fliptets[3]), 1, &fc);
21309  // Second do a 4-to-1 flip on [p,d,a,b],[p,d,b,c],[p,d,c,a],[a,b,c,p].
21310  // This creates a new tet [a,b,c,d].
21311  //flip41(fliptets, 1, 0, 0);
21312  flip41(fliptets, 1, &fc);
21313  //recenttet = fliptets[0];
21314  } else if (loc == ONEDGE) {
21315  // Let the original edge be [e,d] and p is in [e,d]. Assume there are n
21316  // tets sharing at edge [e,d] originally. We number the link vertices
21317  // of [e,d]: p_0, p_1, ..., p_n-1. 'searchtet' is [p,d,p_0,p_1].
21318  // Count the number of tets at edge [e,p] and [p,d] (this is n).
21319  n = 0;
21320  spintet = searchtet;
21321  while (1) {
21322  n++;
21323  fnextself(spintet);
21324  if (spintet.tet == searchtet.tet) break;
21325  }
21326  // Collect the 2n tets containing 'p'.
21327  fliptets = new triface[2 * n];
21328  fliptets[0] = searchtet; // [p,b,p_0,p_1]
21329  for (i = 0; i < (n - 1); i++) {
21330  fnext(fliptets[i], fliptets[i+1]); // [p,d,p_i,p_i+1].
21331  }
21332  eprev(fliptets[0], fliptets[n]);
21333  fnextself(fliptets[n]); // [p_0,p,p_1,e]
21334  esymself(fliptets[n]); // [p,p_0,e,p_1]
21335  eprevself(fliptets[n]); // [e,p,p_0,p_1]
21336  for (i = n; i < (2 * n - 1); i++) {
21337  fnext(fliptets[i], fliptets[i+1]); // [e,p,p_i,p_i+1].
21338  }
21339  // Remove p by a 2n-to-n flip, it is a sequence of n flips:
21340  // - Do a 2-to-3 flip on
21341  // [p_0,p_1,p,d] and
21342  // [p,p_1,p_0,e].
21343  // This produces:
21344  // [e,d,p_0,p_1],
21345  // [e,d,p_1,p] (degenerated), and
21346  // [e,d,p,p_0] (degenerated).
21347  wrktets[0] = fliptets[0]; // [p,d,p_0,p_1]
21348  eprevself(wrktets[0]); // [p_0,p,d,p_1]
21349  esymself(wrktets[0]); // [p,p_0,p_1,d]
21350  enextself(wrktets[0]); // [p_0,p_1,p,d] [0]
21351  wrktets[1] = fliptets[n]; // [e,p,p_0,p_1]
21352  enextself(wrktets[1]); // [p,p_0,e,p_1]
21353  esymself(wrktets[1]); // [p_0,p,p_1,e]
21354  eprevself(wrktets[1]); // [p_1,p_0,p,e] [1]
21355  //flip23(wrktets, 1, 0, 0);
21356  flip23(wrktets, 1, &fc);
21357  // Save the new tet [e,d,p,p_0] (degenerated).
21358  fliptets[n] = wrktets[2];
21359  // Save the new tet [e,d,p_0,p_1].
21360  fliptets[0] = wrktets[0];
21361  // - Repeat from i = 1 to n-2: (n - 2) flips
21362  // - Do a 3-to-2 flip on
21363  // [p,p_i,d,e],
21364  // [p,p_i,e,p_i+1], and
21365  // [p,p_i,p_i+1,d].
21366  // This produces:
21367  // [d,e,p_i+1,p_i], and
21368  // [e,d,p_i+1,p] (degenerated).
21369  for (i = 1; i < (n - 1); i++) {
21370  wrktets[0] = wrktets[1]; // [e,d,p_i,p] (degenerated).
21371  enextself(wrktets[0]); // [d,p_i,e,p] (...)
21372  esymself(wrktets[0]); // [p_i,d,p,e] (...)
21373  eprevself(wrktets[0]); // [p,p_i,d,e] (degenerated) [0].
21374  wrktets[1] = fliptets[n+i]; // [e,p,p_i,p_i+1]
21375  enextself(wrktets[1]); // [p,p_i,e,p_i+1] [1]
21376  wrktets[2] = fliptets[i]; // [p,d,p_i,p_i+1]
21377  eprevself(wrktets[2]); // [p_i,p,d,p_i+1]
21378  esymself(wrktets[2]); // [p,p_i,p_i+1,d] [2]
21379  //flip32(wrktets, 1, 0, 0);
21380  flip32(wrktets, 1, &fc);
21381  // Save the new tet [e,d,p_i,p_i+1]. // FOR DEBUG ONLY
21382  fliptets[i] = wrktets[0]; // [d,e,p_i+1,p_i] // FOR DEBUG ONLY
21383  esymself(fliptets[i]); // [e,d,p_i,p_i+1] // FOR DEBUG ONLY
21384  }
21385  // - Do a 4-to-1 flip on
21386  // [p,p_0,e,d], [d,e,p_0,p],
21387  // [p,p_0,d,p_n-1], [e,p_n-1,p_0,p],
21388  // [p,p_0,p_n-1,e], [p_0,p_n-1,d,p], and
21389  // [e,d,p_n-1,p].
21390  // This produces
21391  // [e,d,p_n-1,p_0] and
21392  // deletes p.
21393  wrktets[3] = wrktets[1]; // [e,d,p_n-1,p] (degenerated) [3]
21394  wrktets[0] = fliptets[n]; // [e,d,p,p_0] (degenerated)
21395  eprevself(wrktets[0]); // [p,e,d,p_0] (...)
21396  esymself(wrktets[0]); // [e,p,p_0,d] (...)
21397  enextself(wrktets[0]); // [p,p_0,e,d] (degenerated) [0]
21398  wrktets[1] = fliptets[n-1]; // [p,d,p_n-1,p_0]
21399  esymself(wrktets[1]); // [d,p,p_0,p_n-1]
21400  enextself(wrktets[1]); // [p,p_0,d,p_n-1] [1]
21401  wrktets[2] = fliptets[2*n-1]; // [e,p,p_n-1,p_0]
21402  enextself(wrktets[2]); // [p_p_n-1,e,p_0]
21403  esymself(wrktets[2]); // [p_n-1,p,p_0,e]
21404  enextself(wrktets[2]); // [p,p_0,p_n-1,e] [2]
21405  //flip41(wrktets, 1, 0, 0);
21406  flip41(wrktets, 1, &fc);
21407  // Save the new tet [e,d,p_n-1,p_0] // FOR DEBUG ONLY
21408  fliptets[n-1] = wrktets[0]; // [e,d,p_n-1,p_0] // FOR DEBUG ONLY
21409  //recenttet = fliptets[0];
21410  }
21411 
21412  delete [] fliptets;
21413 
21414  if (vt == FREESEGVERTEX) {
21415  // Remove the vertex from the surface mesh.
21416  // This will re-create the segment [lpt, rpt] and re-triangulate
21417  // all the facets at the segment.
21418  // Only do lawson flip when subfaces are not recovery yet.
21419  slawson = (checksubfaceflag ? 0 : 1);
21420  spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
21421  sremovevertex(steinerpt, &parentsh, &rightseg, slawson);
21422 
21423  // The original segment is returned in 'rightseg'.
21424  rightseg.shver = 0;
21425  // Insert the new segment.
21426  point2tetorg(lpt, searchtet);
21427  finddirection(&searchtet, rpt);
21428  sstbond1(rightseg, searchtet);
21429  spintet = searchtet;
21430  while (1) {
21431  tssbond1(spintet, rightseg);
21432  fnextself(spintet);
21433  if (spintet.tet == searchtet.tet) break;
21434  }
21435 
21436  if (checksubfaceflag) {
21437  // Insert subfaces at segment [lpt,rpt] into the tetrahedralization.
21438  spivot(rightseg, parentsh);
21439  if (parentsh.sh != NULL) {
21440  spinsh = parentsh;
21441  while (1) {
21442  if (sorg(spinsh) != lpt) {
21443  sesymself(spinsh);
21444  }
21445  apexpt = sapex(spinsh);
21446  // Find the adjacent tet of [lpt,rpt,apexpt];
21447  spintet = searchtet;
21448  while (1) {
21449  if (apex(spintet) == apexpt) {
21450  tsbond(spintet, spinsh);
21451  sesymself(spinsh); // Get to another side of this face.
21452  fsym(spintet, neightet);
21453  tsbond(neightet, spinsh);
21454  sesymself(spinsh); // Get back to the original side.
21455  break;
21456  }
21457  fnextself(spintet);
21458  }
21459  spivotself(spinsh);
21460  if (spinsh.sh == parentsh.sh) break;
21461  }
21462  }
21463  } // if (checksubfaceflag)
21464 
21465  // Clear the set of new subfaces.
21466  caveshbdlist->restart();
21467  } // if (vt == FREESEGVERTEX)
21468 
21469  // The point has been removed.
21470  if (pointtype(steinerpt) != UNUSEDVERTEX) {
21471  setpointtype(steinerpt, UNUSEDVERTEX);
21472  unuverts++;
21473  }
21474  if (vt != VOLVERTEX) {
21475  // Update the correspinding counters.
21476  if (vt == FREESEGVERTEX) {
21477  st_segref_count--;
21478  } else if (vt == FREEFACETVERTEX) {
21479  st_facref_count--;
21480  } else if (vt == FREEVOLVERTEX) {
21481  st_volref_count--;
21482  }
21483  if (steinerleft > 0) steinerleft++;
21484  }
21485 
21486  return 1;
21487 }
21488 
21490 // //
21491 // suppressbdrysteinerpoint() Suppress a boundary Steiner point //
21492 // //
21494 
21495 int tetgenmesh::suppressbdrysteinerpoint(point steinerpt)
21496 {
21497  face parentsh, spinsh, *parysh;
21498  face leftseg, rightseg;
21499  point lpt = NULL, rpt = NULL;
21500  int i;
21501 
21502  verttype vt = pointtype(steinerpt);
21503 
21504  if (vt == FREESEGVERTEX) {
21505  sdecode(point2sh(steinerpt), leftseg);
21506  leftseg.shver = 0;
21507  if (sdest(leftseg) == steinerpt) {
21508  senext(leftseg, rightseg);
21509  spivotself(rightseg);
21510  rightseg.shver = 0;
21511  } else {
21512  rightseg = leftseg;
21513  senext2(rightseg, leftseg);
21514  spivotself(leftseg);
21515  leftseg.shver = 0;
21516  }
21517  lpt = sorg(leftseg);
21518  rpt = sdest(rightseg);
21519  if (b->verbose > 2) {
21520  printf(" Suppressing Steiner point %d in segment (%d, %d).\n",
21521  pointmark(steinerpt), pointmark(lpt), pointmark(rpt));
21522  }
21523  // Get all subfaces at the left segment [lpt, steinerpt].
21524  spivot(leftseg, parentsh);
21525  if (parentsh.sh != NULL) {
21526  // It is not a dangling segment.
21527  spinsh = parentsh;
21528  while (1) {
21529  cavesegshlist->newindex((void **) &parysh);
21530  *parysh = spinsh;
21531  // Orient the face consistently.
21532  if (sorg(*parysh)!= sorg(parentsh)) sesymself(*parysh);
21533  spivotself(spinsh);
21534  if (spinsh.sh == NULL) break;
21535  if (spinsh.sh == parentsh.sh) break;
21536  }
21537  }
21538  if (cavesegshlist->objects < 2) {
21539  // It is a single segment. Not handle it yet.
21540  cavesegshlist->restart();
21541  return 0;
21542  }
21543  } else if (vt == FREEFACETVERTEX) {
21544  if (b->verbose > 2) {
21545  printf(" Suppressing Steiner point %d from facet.\n",
21546  pointmark(steinerpt));
21547  }
21548  sdecode(point2sh(steinerpt), parentsh);
21549  // A facet Steiner point. There are exactly two sectors.
21550  for (i = 0; i < 2; i++) {
21551  cavesegshlist->newindex((void **) &parysh);
21552  *parysh = parentsh;
21553  sesymself(parentsh);
21554  }
21555  } else {
21556  return 0;
21557  }
21558 
21559  triface searchtet, neightet, *parytet;
21560  point pa, pb, pc, pd;
21561  REAL v1[3], v2[3], len, u;
21562 
21563  REAL startpt[3] = {0,}, samplept[3] = {0,}, candpt[3] = {0,};
21564  REAL ori, minvol, smallvol;
21565  int samplesize;
21566  int it, j, k;
21567 
21568  int n = (int) cavesegshlist->objects;
21569  point *newsteiners = new point[n];
21570  for (i = 0; i < n; i++) newsteiners[i] = NULL;
21571 
21572  // Search for each sector an interior vertex.
21573  for (i = 0; i < cavesegshlist->objects; i++) {
21574  parysh = (face *) fastlookup(cavesegshlist, i);
21575  stpivot(*parysh, searchtet);
21576  // Skip it if it is outside.
21577  if (ishulltet(searchtet)) continue;
21578  // Get the "half-ball". Tets in 'cavetetlist' all contain 'steinerpt' as
21579  // opposite. Subfaces in 'caveshlist' all contain 'steinerpt' as apex.
21580  // Moreover, subfaces are oriented towards the interior of the ball.
21581  setpoint2tet(steinerpt, encode(searchtet));
21582  getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist);
21583  // Calculate the searching vector.
21584  pa = sorg(*parysh);
21585  pb = sdest(*parysh);
21586  pc = sapex(*parysh);
21587  facenormal(pa, pb, pc, v1, 1, NULL);
21588  len = sqrt(dot(v1, v1));
21589  v1[0] /= len;
21590  v1[1] /= len;
21591  v1[2] /= len;
21592  if (vt == FREESEGVERTEX) {
21593  parysh = (face *) fastlookup(cavesegshlist, (i + 1) % n);
21594  pd = sapex(*parysh);
21595  facenormal(pb, pa, pd, v2, 1, NULL);
21596  len = sqrt(dot(v2, v2));
21597  v2[0] /= len;
21598  v2[1] /= len;
21599  v2[2] /= len;
21600  // Average the two vectors.
21601  v1[0] = 0.5 * (v1[0] + v2[0]);
21602  v1[1] = 0.5 * (v1[1] + v2[1]);
21603  v1[2] = 0.5 * (v1[2] + v2[2]);
21604  }
21605  // Search the intersection of the ray starting from 'steinerpt' to
21606  // the search direction 'v1' and the shell of the half-ball.
21607  // - Construct an endpoint.
21608  len = distance(pa, pb);
21609  v2[0] = steinerpt[0] + len * v1[0];
21610  v2[1] = steinerpt[1] + len * v1[1];
21611  v2[2] = steinerpt[2] + len * v1[2];
21612  for (j = 0; j < cavetetlist->objects; j++) {
21613  parytet = (triface *) fastlookup(cavetetlist, j);
21614  pa = org(*parytet);
21615  pb = dest(*parytet);
21616  pc = apex(*parytet);
21617  // Test if the ray startpt->v2 lies in the cone: where 'steinerpt'
21618  // is the apex, and three sides are defined by the triangle
21619  // [pa, pb, pc].
21620  ori = orient3d(steinerpt, pa, pb, v2);
21621  if (ori >= 0) {
21622  ori = orient3d(steinerpt, pb, pc, v2);
21623  if (ori >= 0) {
21624  ori = orient3d(steinerpt, pc, pa, v2);
21625  if (ori >= 0) {
21626  // Found! Calculate the intersection.
21627  planelineint(pa, pb, pc, steinerpt, v2, startpt, &u);
21628  break;
21629  }
21630  }
21631  }
21632  } // j
21633  if (j == cavetetlist->objects) {
21634  break; // There is no intersection!! Debug is needed.
21635  }
21636  // Close the ball by adding the subfaces.
21637  for (j = 0; j < caveshlist->objects; j++) {
21638  parysh = (face *) fastlookup(caveshlist, j);
21639  stpivot(*parysh, neightet);
21640  cavetetlist->newindex((void **) &parytet);
21641  *parytet = neightet;
21642  }
21643  // Search a best point inside the segment [startpt, steinerpt].
21644  it = 0;
21645  samplesize = 100;
21646  v1[0] = steinerpt[0] - startpt[0];
21647  v1[1] = steinerpt[1] - startpt[1];
21648  v1[2] = steinerpt[2] - startpt[2];
21649  minvol = -1.0;
21650  while (it < 3) {
21651  for (j = 1; j < samplesize - 1; j++) {
21652  samplept[0] = startpt[0] + ((REAL) j / (REAL) samplesize) * v1[0];
21653  samplept[1] = startpt[1] + ((REAL) j / (REAL) samplesize) * v1[1];
21654  samplept[2] = startpt[2] + ((REAL) j / (REAL) samplesize) * v1[2];
21655  // Find the minimum volume for 'samplept'.
21656  smallvol = -1;
21657  for (k = 0; k < cavetetlist->objects; k++) {
21658  parytet = (triface *) fastlookup(cavetetlist, k);
21659  pa = org(*parytet);
21660  pb = dest(*parytet);
21661  pc = apex(*parytet);
21662  ori = orient3d(pb, pa, pc, samplept);
21663  {
21664  // [2017-10-15] Rounding
21665  REAL lab = distance(pa, pb);
21666  REAL lbc = distance(pb, pc);
21667  REAL lca = distance(pc, pa);
21668  REAL lv = (lab + lbc + lca) / 3.0;
21669  REAL l3 = lv*lv*lv;
21670  if (fabs(ori) / l3 < 1e-8) ori = 0.0;
21671  }
21672  if (ori <= 0) {
21673  break; // An invalid tet.
21674  }
21675  if (smallvol == -1) {
21676  smallvol = ori;
21677  } else {
21678  if (ori < smallvol) smallvol = ori;
21679  }
21680  } // k
21681  if (k == cavetetlist->objects) {
21682  // Found a valid point. Remember it.
21683  if (minvol == -1.0) {
21684  candpt[0] = samplept[0];
21685  candpt[1] = samplept[1];
21686  candpt[2] = samplept[2];
21687  minvol = smallvol;
21688  } else {
21689  if (minvol < smallvol) {
21690  // It is a better location. Remember it.
21691  candpt[0] = samplept[0];
21692  candpt[1] = samplept[1];
21693  candpt[2] = samplept[2];
21694  minvol = smallvol;
21695  } else {
21696  // No improvement of smallest volume.
21697  // Since we are searching along the line [startpt, steinerpy],
21698  // The smallest volume can only be decreased later.
21699  break;
21700  }
21701  }
21702  }
21703  } // j
21704  if (minvol > 0) break;
21705  samplesize *= 10;
21706  it++;
21707  } // while (it < 3)
21708  if (minvol == -1.0) {
21709  // Failed to find a valid point.
21710  cavetetlist->restart();
21711  caveshlist->restart();
21712  break;
21713  }
21714  // Create a new Steiner point inside this section.
21715  makepoint(&(newsteiners[i]), FREEVOLVERTEX);
21716  newsteiners[i][0] = candpt[0];
21717  newsteiners[i][1] = candpt[1];
21718  newsteiners[i][2] = candpt[2];
21719  cavetetlist->restart();
21720  caveshlist->restart();
21721  } // i
21722 
21723  if (i < cavesegshlist->objects) {
21724  // Failed to suppress the vertex.
21725  for (; i > 0; i--) {
21726  if (newsteiners[i - 1] != NULL) {
21727  pointdealloc(newsteiners[i - 1]);
21728  }
21729  }
21730  delete [] newsteiners;
21731  cavesegshlist->restart();
21732  return 0;
21733  }
21734 
21735  // Remove p from the segment or the facet.
21736  triface newtet, newface, spintet;
21737  face newsh, neighsh;
21738  face *splitseg, checkseg;
21739  int slawson = 0; // Do not do flip afterword.
21740  int t1ver;
21741 
21742  if (vt == FREESEGVERTEX) {
21743  // Detach 'leftseg' and 'rightseg' from their adjacent tets.
21744  // These two subsegments will be deleted.
21745  sstpivot1(leftseg, neightet);
21746  spintet = neightet;
21747  while (1) {
21748  tssdissolve1(spintet);
21749  fnextself(spintet);
21750  if (spintet.tet == neightet.tet) break;
21751  }
21752  sstpivot1(rightseg, neightet);
21753  spintet = neightet;
21754  while (1) {
21755  tssdissolve1(spintet);
21756  fnextself(spintet);
21757  if (spintet.tet == neightet.tet) break;
21758  }
21759  }
21760 
21761  // Loop through all sectors bounded by facets at this segment.
21762  // Within each sector, create a new Steiner point 'np', and replace 'p'
21763  // by 'np' for all tets in this sector.
21764  for (i = 0; i < cavesegshlist->objects; i++) {
21765  parysh = (face *) fastlookup(cavesegshlist, i);
21766  // 'parysh' is the face [lpt, steinerpt, #].
21767  stpivot(*parysh, neightet);
21768  // Get all tets in this sector.
21769  setpoint2tet(steinerpt, encode(neightet));
21770  getvertexstar(0, steinerpt, cavetetlist, NULL, caveshlist);
21771  if (!ishulltet(neightet)) {
21772  // Within each tet in the ball, replace 'p' by 'np'.
21773  for (j = 0; j < cavetetlist->objects; j++) {
21774  parytet = (triface *) fastlookup(cavetetlist, j);
21775  setoppo(*parytet, newsteiners[i]);
21776  } // j
21777  // Point to a parent tet.
21778  parytet = (triface *) fastlookup(cavetetlist, 0);
21779  setpoint2tet(newsteiners[i], (tetrahedron) (parytet->tet));
21780  st_volref_count++;
21781  if (steinerleft > 0) steinerleft--;
21782  }
21783  // Disconnect the set of boundary faces. They're temporarily open faces.
21784  // They will be connected to the new tets after 'p' is removed.
21785  for (j = 0; j < caveshlist->objects; j++) {
21786  // Get a boundary face.
21787  parysh = (face *) fastlookup(caveshlist, j);
21788  stpivot(*parysh, neightet);
21789  //assert(apex(neightet) == newpt);
21790  // Clear the connection at this face.
21791  dissolve(neightet);
21792  tsdissolve(neightet);
21793  }
21794  // Clear the working lists.
21795  cavetetlist->restart();
21796  caveshlist->restart();
21797  } // i
21798  cavesegshlist->restart();
21799 
21800  if (vt == FREESEGVERTEX) {
21801  spivot(rightseg, parentsh); // 'rightseg' has p as its origin.
21802  splitseg = &rightseg;
21803  } else {
21804  if (sdest(parentsh) == steinerpt) {
21805  senextself(parentsh);
21806  } else if (sapex(parentsh) == steinerpt) {
21807  senext2self(parentsh);
21808  }
21809  splitseg = NULL;
21810  }
21811  sremovevertex(steinerpt, &parentsh, splitseg, slawson);
21812 
21813  if (vt == FREESEGVERTEX) {
21814  // The original segment is returned in 'rightseg'.
21815  rightseg.shver = 0;
21816  }
21817 
21818  // For each new subface, create two new tets at each side of it.
21819  // Both of the two new tets have its opposite be dummypoint.
21820  for (i = 0; i < caveshbdlist->objects; i++) {
21821  parysh = (face *) fastlookup(caveshbdlist, i);
21822  sinfect(*parysh); // Mark it for connecting new tets.
21823  newsh = *parysh;
21824  pa = sorg(newsh);
21825  pb = sdest(newsh);
21826  pc = sapex(newsh);
21827  maketetrahedron(&newtet);
21828  maketetrahedron(&neightet);
21829  setvertices(newtet, pa, pb, pc, dummypoint);
21830  setvertices(neightet, pb, pa, pc, dummypoint);
21831  bond(newtet, neightet);
21832  tsbond(newtet, newsh);
21833  sesymself(newsh);
21834  tsbond(neightet, newsh);
21835  }
21836  // Temporarily increase the hullsize.
21837  hullsize += (caveshbdlist->objects * 2l);
21838 
21839  if (vt == FREESEGVERTEX) {
21840  // Connecting new tets at the recovered segment.
21841  spivot(rightseg, parentsh);
21842  spinsh = parentsh;
21843  while (1) {
21844  if (sorg(spinsh) != lpt) sesymself(spinsh);
21845  // Get the new tet at this subface.
21846  stpivot(spinsh, newtet);
21847  tssbond1(newtet, rightseg);
21848  // Go to the other face at this segment.
21849  spivot(spinsh, neighsh);
21850  if (sorg(neighsh) != lpt) sesymself(neighsh);
21851  sesymself(neighsh);
21852  stpivot(neighsh, neightet);
21853  tssbond1(neightet, rightseg);
21854  sstbond1(rightseg, neightet);
21855  // Connecting two adjacent tets at this segment.
21856  esymself(newtet);
21857  esymself(neightet);
21858  // Connect the two tets (at rightseg) together.
21859  bond(newtet, neightet);
21860  // Go to the next subface.
21861  spivotself(spinsh);
21862  if (spinsh.sh == parentsh.sh) break;
21863  }
21864  }
21865 
21866  // Connecting new tets at new subfaces together.
21867  for (i = 0; i < caveshbdlist->objects; i++) {
21868  parysh = (face *) fastlookup(caveshbdlist, i);
21869  newsh = *parysh;
21870  //assert(sinfected(newsh));
21871  // Each new subface contains two new tets.
21872  for (k = 0; k < 2; k++) {
21873  stpivot(newsh, newtet);
21874  for (j = 0; j < 3; j++) {
21875  // Check if this side is open.
21876  esym(newtet, newface);
21877  if (newface.tet[newface.ver & 3] == NULL) {
21878  // An open face. Connect it to its adjacent tet.
21879  sspivot(newsh, checkseg);
21880  if (checkseg.sh != NULL) {
21881  // A segment. It must not be the recovered segment.
21882  tssbond1(newtet, checkseg);
21883  sstbond1(checkseg, newtet);
21884  }
21885  spivot(newsh, neighsh);
21886  if (neighsh.sh != NULL) {
21887  // The adjacent subface exists. It's not a dangling segment.
21888  if (sorg(neighsh) != sdest(newsh)) sesymself(neighsh);
21889  stpivot(neighsh, neightet);
21890  if (sinfected(neighsh)) {
21891  esymself(neightet);
21892  } else {
21893  // Search for an open face at this edge.
21894  spintet = neightet;
21895  while (1) {
21896  esym(spintet, searchtet);
21897  fsym(searchtet, spintet);
21898  if (spintet.tet == NULL) break;
21899  }
21900  // Found an open face at 'searchtet'.
21901  neightet = searchtet;
21902  }
21903  } else {
21904  // The edge (at 'newsh') is a dangling segment.
21905  // Get an adjacent tet at this segment.
21906  sstpivot1(checkseg, neightet);
21907  if (org(neightet) != sdest(newsh)) esymself(neightet);
21908  // Search for an open face at this edge.
21909  spintet = neightet;
21910  while (1) {
21911  esym(spintet, searchtet);
21912  fsym(searchtet, spintet);
21913  if (spintet.tet == NULL) break;
21914  }
21915  // Found an open face at 'searchtet'.
21916  neightet = searchtet;
21917  }
21918  pc = apex(newface);
21919  if (apex(neightet) == steinerpt) {
21920  // Exterior case. The 'neightet' is a hull tet which contain
21921  // 'steinerpt'. It will be deleted after 'steinerpt' is removed.
21922  caveoldtetlist->newindex((void **) &parytet);
21923  *parytet = neightet;
21924  // Connect newface to the adjacent hull tet of 'neightet', which
21925  // has the same edge as 'newface', and does not has 'steinerpt'.
21926  fnextself(neightet);
21927  } else {
21928  if (pc == dummypoint) {
21929  if (apex(neightet) != dummypoint) {
21930  setapex(newface, apex(neightet));
21931  // A hull tet has turned into an interior tet.
21932  hullsize--; // Must update the hullsize.
21933  }
21934  }
21935  }
21936  bond(newface, neightet);
21937  } // if (newface.tet[newface.ver & 3] == NULL)
21938  enextself(newtet);
21939  senextself(newsh);
21940  } // j
21941  sesymself(newsh);
21942  } // k
21943  } // i
21944 
21945  // Unmark all new subfaces.
21946  for (i = 0; i < caveshbdlist->objects; i++) {
21947  parysh = (face *) fastlookup(caveshbdlist, i);
21948  suninfect(*parysh);
21949  }
21950  caveshbdlist->restart();
21951 
21952  if (caveoldtetlist->objects > 0l) {
21953  // Delete hull tets which contain 'steinerpt'.
21954  for (i = 0; i < caveoldtetlist->objects; i++) {
21955  parytet = (triface *) fastlookup(caveoldtetlist, i);
21956  tetrahedrondealloc(parytet->tet);
21957  }
21958  // Must update the hullsize.
21959  hullsize -= caveoldtetlist->objects;
21960  caveoldtetlist->restart();
21961  }
21962 
21963  setpointtype(steinerpt, UNUSEDVERTEX);
21964  unuverts++;
21965  if (vt == FREESEGVERTEX) {
21966  st_segref_count--;
21967  } else { // vt == FREEFACETVERTEX
21968  st_facref_count--;
21969  }
21970  if (steinerleft > 0) steinerleft++; // We've removed a Steiner points.
21971 
21972 
21973  point *parypt;
21974  int steinercount = 0;
21975 
21976  int bak_fliplinklevel = b->fliplinklevel;
21977  b->fliplinklevel = 100000; // Unlimited flip level.
21978 
21979  // Try to remove newly added Steiner points.
21980  for (i = 0; i < n; i++) {
21981  if (newsteiners[i] != NULL) {
21982  if (!removevertexbyflips(newsteiners[i])) {
21983  if (b->supsteiner_level > 0) { // Not -Y/0
21984  // Save it in subvertstack for removal.
21985  subvertstack->newindex((void **) &parypt);
21986  *parypt = newsteiners[i];
21987  }
21988  steinercount++;
21989  }
21990  }
21991  }
21992 
21993  b->fliplinklevel = bak_fliplinklevel;
21994 
21995  if (steinercount > 0) {
21996  if (b->verbose > 2) {
21997  printf(" Added %d interior Steiner points.\n", steinercount);
21998  }
21999  }
22000 
22001  delete [] newsteiners;
22002 
22003  return 1;
22004 }
22005 
22006 
22008 // //
22009 // suppresssteinerpoints() Suppress Steiner points. //
22010 // //
22011 // All Steiner points have been saved in 'subvertstack' in the routines //
22012 // carveholes() and suppresssteinerpoint(). //
22013 // Each Steiner point is either removed or shifted into the interior. //
22014 // //
22016 
22017 int tetgenmesh::suppresssteinerpoints()
22018 {
22019 
22020  if (!b->quiet) {
22021  printf("Suppressing Steiner points ...\n");
22022  }
22023 
22024  point rempt, *parypt;
22025 
22026  int bak_fliplinklevel = b->fliplinklevel;
22027  b->fliplinklevel = 100000; // Unlimited flip level.
22028  int suppcount = 0, remcount = 0;
22029  int i;
22030 
22031  // Try to suppress boundary Steiner points.
22032  for (i = 0; i < subvertstack->objects; i++) {
22033  parypt = (point *) fastlookup(subvertstack, i);
22034  rempt = *parypt;
22035  if (pointtype(rempt) != UNUSEDVERTEX) {
22036  if ((pointtype(rempt) == FREESEGVERTEX) ||
22037  (pointtype(rempt) == FREEFACETVERTEX)) {
22038  if (suppressbdrysteinerpoint(rempt)) {
22039  suppcount++;
22040  }
22041  }
22042  }
22043  } // i
22044 
22045  if (suppcount > 0) {
22046  if (b->verbose) {
22047  printf(" Suppressed %d boundary Steiner points.\n", suppcount);
22048  }
22049  }
22050 
22051  if (b->supsteiner_level > 0) { // -Y/1
22052  for (i = 0; i < subvertstack->objects; i++) {
22053  parypt = (point *) fastlookup(subvertstack, i);
22054  rempt = *parypt;
22055  if (pointtype(rempt) != UNUSEDVERTEX) {
22056  if (pointtype(rempt) == FREEVOLVERTEX) {
22057  if (removevertexbyflips(rempt)) {
22058  remcount++;
22059  }
22060  }
22061  }
22062  }
22063  }
22064 
22065  if (remcount > 0) {
22066  if (b->verbose) {
22067  printf(" Removed %d interior Steiner points.\n", remcount);
22068  }
22069  }
22070 
22071  b->fliplinklevel = bak_fliplinklevel;
22072 
22073  if (b->supsteiner_level > 1) { // -Y/2
22074  // Smooth interior Steiner points.
22075  optparameters opm;
22076  triface *parytet;
22077  point *ppt;
22078  REAL ori;
22079  int smtcount, count, ivcount;
22080  int nt, j;
22081 
22082  // Point smooth options.
22083  opm.max_min_volume = 1;
22084  opm.numofsearchdirs = 20;
22085  opm.searchstep = 0.001;
22086  opm.maxiter = 30; // Limit the maximum iterations.
22087 
22088  smtcount = 0;
22089 
22090  do {
22091 
22092  nt = 0;
22093 
22094  while (1) {
22095  count = 0;
22096  ivcount = 0; // Clear the inverted count.
22097 
22098  for (i = 0; i < subvertstack->objects; i++) {
22099  parypt = (point *) fastlookup(subvertstack, i);
22100  rempt = *parypt;
22101  if (pointtype(rempt) == FREEVOLVERTEX) {
22102  getvertexstar(1, rempt, cavetetlist, NULL, NULL);
22103  // Calculate the initial smallest volume (maybe zero or negative).
22104  for (j = 0; j < cavetetlist->objects; j++) {
22105  parytet = (triface *) fastlookup(cavetetlist, j);
22106  ppt = (point *) &(parytet->tet[4]);
22107  ori = orient3dfast(ppt[1], ppt[0], ppt[2], ppt[3]);
22108  if (j == 0) {
22109  opm.initval = ori;
22110  } else {
22111  if (opm.initval > ori) opm.initval = ori;
22112  }
22113  }
22114  if (smoothpoint(rempt, cavetetlist, 1, &opm)) {
22115  count++;
22116  }
22117  if (opm.imprval <= 0.0) {
22118  ivcount++; // The mesh contains inverted elements.
22119  }
22120  cavetetlist->restart();
22121  }
22122  } // i
22123 
22124  smtcount += count;
22125 
22126  if (count == 0) {
22127  // No point has been smoothed.
22128  break;
22129  }
22130 
22131  nt++;
22132  if (nt > 2) {
22133  break; // Already three iterations.
22134  }
22135  } // while
22136 
22137  if (ivcount > 0) {
22138  // There are inverted elements!
22139  if (opm.maxiter > 0) {
22140  // Set unlimited smoothing steps. Try again.
22141  opm.numofsearchdirs = 30;
22142  opm.searchstep = 0.0001;
22143  opm.maxiter = -1;
22144  continue;
22145  }
22146  }
22147 
22148  break;
22149  } while (1); // Additional loop for (ivcount > 0)
22150 
22151  if (ivcount > 0) {
22152  printf("BUG Report! The mesh contain inverted elements.\n");
22153  }
22154 
22155  if (b->verbose) {
22156  if (smtcount > 0) {
22157  printf(" Smoothed %d Steiner points.\n", smtcount);
22158  }
22159  }
22160  } // -Y2
22161 
22162  subvertstack->restart();
22163 
22164  return 1;
22165 }
22166 
22168 // //
22169 // recoverboundary() Recover segments and facets. //
22170 // //
22172 
22173 void tetgenmesh::recoverboundary(clock_t& tv)
22174 {
22175  arraypool *misseglist, *misshlist;
22176  arraypool *bdrysteinerptlist;
22177  face searchsh, *parysh;
22178  face searchseg, *paryseg;
22179  point rempt, *parypt;
22180  long ms; // The number of missing segments/subfaces.
22181  int nit; // The number of iterations.
22182  int s, i;
22183 
22184  // Counters.
22185  long bak_segref_count, bak_facref_count, bak_volref_count;
22186 
22187  if (!b->quiet) {
22188  printf("Recovering boundaries...\n");
22189  }
22190 
22191 
22192  if (b->verbose) {
22193  printf(" Recovering segments.\n");
22194  }
22195 
22196  // Segments will be introduced.
22197  checksubsegflag = 1;
22198 
22199  misseglist = new arraypool(sizeof(face), 8);
22200  bdrysteinerptlist = new arraypool(sizeof(point), 8);
22201 
22202  // In random order.
22203  subsegs->traversalinit();
22204  for (i = 0; i < subsegs->items; i++) {
22205  s = randomnation(i + 1);
22206  // Move the s-th seg to the i-th.
22207  subsegstack->newindex((void **) &paryseg);
22208  *paryseg = * (face *) fastlookup(subsegstack, s);
22209  // Put i-th seg to be the s-th.
22210  searchseg.sh = shellfacetraverse(subsegs);
22211  paryseg = (face *) fastlookup(subsegstack, s);
22212  *paryseg = searchseg;
22213  }
22214 
22215  // The init number of missing segments.
22216  ms = subsegs->items;
22217  nit = 0;
22218  if (b->fliplinklevel < 0) {
22219  autofliplinklevel = 1; // Init value.
22220  }
22221 
22222  // First, trying to recover segments by only doing flips.
22223  while (1) {
22224  recoversegments(misseglist, 0, 0);
22225 
22226  if (misseglist->objects > 0) {
22227  if (b->fliplinklevel >= 0) {
22228  break;
22229  } else {
22230  if (misseglist->objects >= ms) {
22231  nit++;
22232  if (nit >= 3) {
22233  //break;
22234  // Do the last round with unbounded flip link level.
22235  b->fliplinklevel = 100000;
22236  }
22237  } else {
22238  ms = misseglist->objects;
22239  if (nit > 0) {
22240  nit--;
22241  }
22242  }
22243  for (i = 0; i < misseglist->objects; i++) {
22244  subsegstack->newindex((void **) &paryseg);
22245  *paryseg = * (face *) fastlookup(misseglist, i);
22246  }
22247  misseglist->restart();
22248  autofliplinklevel+=b->fliplinklevelinc;
22249  }
22250  } else {
22251  // All segments are recovered.
22252  break;
22253  }
22254  } // while (1)
22255 
22256  if (b->verbose) {
22257  printf(" %ld (%ld) segments are recovered (missing).\n",
22258  subsegs->items - misseglist->objects, misseglist->objects);
22259  }
22260 
22261  if (misseglist->objects > 0) {
22262  // Second, trying to recover segments by doing more flips (fullsearch).
22263  while (misseglist->objects > 0) {
22264  ms = misseglist->objects;
22265  for (i = 0; i < misseglist->objects; i++) {
22266  subsegstack->newindex((void **) &paryseg);
22267  *paryseg = * (face *) fastlookup(misseglist, i);
22268  }
22269  misseglist->restart();
22270 
22271  recoversegments(misseglist, 1, 0);
22272 
22273  if (misseglist->objects < ms) {
22274  // The number of missing segments is reduced.
22275  continue;
22276  } else {
22277  break;
22278  }
22279  }
22280  if (b->verbose) {
22281  printf(" %ld (%ld) segments are recovered (missing).\n",
22282  subsegs->items - misseglist->objects, misseglist->objects);
22283  }
22284  }
22285 
22286  if (misseglist->objects > 0) {
22287  // Third, trying to recover segments by doing more flips (fullsearch)
22288  // and adding Steiner points in the volume.
22289  while (misseglist->objects > 0) {
22290  ms = misseglist->objects;
22291  for (i = 0; i < misseglist->objects; i++) {
22292  subsegstack->newindex((void **) &paryseg);
22293  *paryseg = * (face *) fastlookup(misseglist, i);
22294  }
22295  misseglist->restart();
22296 
22297  recoversegments(misseglist, 1, 1);
22298 
22299  if (misseglist->objects < ms) {
22300  // The number of missing segments is reduced.
22301  continue;
22302  } else {
22303  break;
22304  }
22305  }
22306  if (b->verbose) {
22307  printf(" Added %ld Steiner points in volume.\n", st_volref_count);
22308  }
22309  }
22310 
22311  if (misseglist->objects > 0) {
22312  // Last, trying to recover segments by doing more flips (fullsearch),
22313  // and adding Steiner points in the volume, and splitting segments.
22314  long bak_inpoly_count = st_volref_count; //st_inpoly_count;
22315  for (i = 0; i < misseglist->objects; i++) {
22316  subsegstack->newindex((void **) &paryseg);
22317  *paryseg = * (face *) fastlookup(misseglist, i);
22318  }
22319  misseglist->restart();
22320 
22321  recoversegments(misseglist, 1, 2);
22322 
22323  if (b->verbose) {
22324  printf(" Added %ld Steiner points in segments.\n", st_segref_count);
22325  if (st_volref_count > bak_inpoly_count) {
22326  printf(" Added another %ld Steiner points in volume.\n",
22327  st_volref_count - bak_inpoly_count);
22328  }
22329  }
22330  }
22331 
22332 
22333  if (st_segref_count > 0) {
22334  // Try to remove the Steiner points added in segments.
22335  bak_segref_count = st_segref_count;
22336  bak_volref_count = st_volref_count;
22337  for (i = 0; i < subvertstack->objects; i++) {
22338  // Get the Steiner point.
22339  parypt = (point *) fastlookup(subvertstack, i);
22340  rempt = *parypt;
22341  if (!removevertexbyflips(rempt)) {
22342  // Save it in list.
22343  bdrysteinerptlist->newindex((void **) &parypt);
22344  *parypt = rempt;
22345  }
22346  }
22347  if (b->verbose) {
22348  if (st_segref_count < bak_segref_count) {
22349  if (bak_volref_count < st_volref_count) {
22350  printf(" Suppressed %ld Steiner points in segments.\n",
22351  st_volref_count - bak_volref_count);
22352  }
22353  if ((st_segref_count + (st_volref_count - bak_volref_count)) <
22354  bak_segref_count) {
22355  printf(" Removed %ld Steiner points in segments.\n",
22356  bak_segref_count -
22357  (st_segref_count + (st_volref_count - bak_volref_count)));
22358  }
22359  }
22360  }
22361  subvertstack->restart();
22362  }
22363 
22364 
22365  tv = clock();
22366 
22367  if (b->verbose) {
22368  printf(" Recovering facets.\n");
22369  }
22370 
22371  // Subfaces will be introduced.
22372  checksubfaceflag = 1;
22373 
22374  misshlist = new arraypool(sizeof(face), 8);
22375 
22376  // Randomly order the subfaces.
22377  subfaces->traversalinit();
22378  for (i = 0; i < subfaces->items; i++) {
22379  s = randomnation(i + 1);
22380  // Move the s-th subface to the i-th.
22381  subfacstack->newindex((void **) &parysh);
22382  *parysh = * (face *) fastlookup(subfacstack, s);
22383  // Put i-th subface to be the s-th.
22384  searchsh.sh = shellfacetraverse(subfaces);
22385  parysh = (face *) fastlookup(subfacstack, s);
22386  *parysh = searchsh;
22387  }
22388 
22389  ms = subfaces->items;
22390  nit = 0;
22391  b->fliplinklevel = -1; // Init.
22392  if (b->fliplinklevel < 0) {
22393  autofliplinklevel = 1; // Init value.
22394  }
22395 
22396  while (1) {
22397  recoversubfaces(misshlist, 0);
22398 
22399  if (misshlist->objects > 0) {
22400  if (b->fliplinklevel >= 0) {
22401  break;
22402  } else {
22403  if (misshlist->objects >= ms) {
22404  nit++;
22405  if (nit >= 3) {
22406  //break;
22407  // Do the last round with unbounded flip link level.
22408  b->fliplinklevel = 100000;
22409  }
22410  } else {
22411  ms = misshlist->objects;
22412  if (nit > 0) {
22413  nit--;
22414  }
22415  }
22416  for (i = 0; i < misshlist->objects; i++) {
22417  subfacstack->newindex((void **) &parysh);
22418  *parysh = * (face *) fastlookup(misshlist, i);
22419  }
22420  misshlist->restart();
22421  autofliplinklevel+=b->fliplinklevelinc;
22422  }
22423  } else {
22424  // All subfaces are recovered.
22425  break;
22426  }
22427  } // while (1)
22428 
22429  if (b->verbose) {
22430  printf(" %ld (%ld) subfaces are recovered (missing).\n",
22431  subfaces->items - misshlist->objects, misshlist->objects);
22432  }
22433 
22434  if (misshlist->objects > 0) {
22435  // There are missing subfaces. Add Steiner points.
22436  for (i = 0; i < misshlist->objects; i++) {
22437  subfacstack->newindex((void **) &parysh);
22438  *parysh = * (face *) fastlookup(misshlist, i);
22439  }
22440  misshlist->restart();
22441 
22442  recoversubfaces(NULL, 1);
22443 
22444  if (b->verbose) {
22445  printf(" Added %ld Steiner points in facets.\n", st_facref_count);
22446  }
22447  }
22448 
22449 
22450  if (st_facref_count > 0) {
22451  // Try to remove the Steiner points added in facets.
22452  bak_facref_count = st_facref_count;
22453  for (i = 0; i < subvertstack->objects; i++) {
22454  // Get the Steiner point.
22455  parypt = (point *) fastlookup(subvertstack, i);
22456  rempt = *parypt;
22457  if (!removevertexbyflips(*parypt)) {
22458  // Save it in list.
22459  bdrysteinerptlist->newindex((void **) &parypt);
22460  *parypt = rempt;
22461  }
22462  }
22463  if (b->verbose) {
22464  if (st_facref_count < bak_facref_count) {
22465  printf(" Removed %ld Steiner points in facets.\n",
22466  bak_facref_count - st_facref_count);
22467  }
22468  }
22469  subvertstack->restart();
22470  }
22471 
22472 
22473  if (bdrysteinerptlist->objects > 0) {
22474  if (b->verbose) {
22475  printf(" %ld Steiner points remained in boundary.\n",
22476  bdrysteinerptlist->objects);
22477  }
22478  } // if
22479 
22480 
22481  // Accumulate the dynamic memory.
22482  totalworkmemory += (misseglist->totalmemory + misshlist->totalmemory +
22483  bdrysteinerptlist->totalmemory);
22484 
22485  delete bdrysteinerptlist;
22486  delete misseglist;
22487  delete misshlist;
22488 }
22489 
22493 
22494 
22498 
22500 // //
22501 // carveholes() Remove tetrahedra not in the mesh domain. //
22502 // //
22504 
22505 
22506 void tetgenmesh::carveholes()
22507 {
22508  arraypool *tetarray, *hullarray;
22509  triface tetloop, neightet, *parytet, *parytet1;
22510  triface *regiontets = NULL;
22511  face checksh, *parysh;
22512  face checkseg;
22513  point ptloop, *parypt;
22514  int t1ver;
22515  int i, j, k;
22516 
22517  if (!b->quiet) {
22518  if (b->convex) {
22519  printf("Marking exterior tetrahedra ...\n");
22520  } else {
22521  printf("Removing exterior tetrahedra ...\n");
22522  }
22523  }
22524 
22525  // Initialize the pool of exterior tets.
22526  tetarray = new arraypool(sizeof(triface), 10);
22527  hullarray = new arraypool(sizeof(triface), 10);
22528 
22529  // Collect unprotected tets and hull tets.
22530  tetrahedrons->traversalinit();
22531  tetloop.ver = 11; // The face opposite to dummypoint.
22532  tetloop.tet = alltetrahedrontraverse();
22533  while (tetloop.tet != (tetrahedron *) NULL) {
22534  if (ishulltet(tetloop)) {
22535  // Is this side protected by a subface?
22536  if (!issubface(tetloop)) {
22537  // Collect an unprotected hull tet and tet.
22538  infect(tetloop);
22539  hullarray->newindex((void **) &parytet);
22540  *parytet = tetloop;
22541  // tetloop's face number is 11 & 3 = 3.
22542  decode(tetloop.tet[3], neightet);
22543  if (!infected(neightet)) {
22544  infect(neightet);
22545  tetarray->newindex((void **) &parytet);
22546  *parytet = neightet;
22547  }
22548  }
22549  }
22550  tetloop.tet = alltetrahedrontraverse();
22551  }
22552 
22553  if (in->numberofholes > 0) {
22554  // Mark as infected any tets inside volume holes.
22555  for (i = 0; i < 3 * in->numberofholes; i += 3) {
22556  // Search a tet containing the i-th hole point.
22557  neightet.tet = NULL;
22558  randomsample(&(in->holelist[i]), &neightet);
22559  if (locate(&(in->holelist[i]), &neightet) != OUTSIDE) {
22560  // The tet 'neightet' contain this point.
22561  if (!infected(neightet)) {
22562  infect(neightet);
22563  tetarray->newindex((void **) &parytet);
22564  *parytet = neightet;
22565  // Add its adjacent tet if it is not protected.
22566  if (!issubface(neightet)) {
22567  decode(neightet.tet[neightet.ver & 3], tetloop);
22568  if (!infected(tetloop)) {
22569  infect(tetloop);
22570  if (ishulltet(tetloop)) {
22571  hullarray->newindex((void **) &parytet);
22572  } else {
22573  tetarray->newindex((void **) &parytet);
22574  }
22575  *parytet = tetloop;
22576  }
22577  }
22578  else {
22579  // It is protected. Check if its adjacent tet is a hull tet.
22580  decode(neightet.tet[neightet.ver & 3], tetloop);
22581  if (ishulltet(tetloop)) {
22582  // It is hull tet, add it into the list. Moreover, the subface
22583  // is dead, i.e., both sides are in exterior.
22584  if (!infected(tetloop)) {
22585  infect(tetloop);
22586  hullarray->newindex((void **) &parytet);
22587  *parytet = tetloop;
22588  }
22589  }
22590  if (infected(tetloop)) {
22591  // Both sides of this subface are in exterior.
22592  tspivot(neightet, checksh);
22593  sinfect(checksh); // Only queue it once.
22594  subfacstack->newindex((void **) &parysh);
22595  *parysh = checksh;
22596  }
22597  }
22598  } // if (!infected(neightet))
22599  } else {
22600  // A hole point locates outside of the convex hull.
22601  if (!b->quiet) {
22602  printf("Warning: The %d-th hole point ", i/3 + 1);
22603  printf("lies outside the convex hull.\n");
22604  }
22605  }
22606  } // i
22607  } // if (in->numberofholes > 0)
22608 
22609  if (b->hole_mesh && (b->hole_mesh_filename[0] != 0)) {
22610  // A hole mesh (***.ele) is given.
22611  //enum tetgenbehavior::objecttype object;
22612  char filebasename[256];
22613  strcpy(filebasename, b->hole_mesh_filename);
22614  //object = tetgenbehavior::MESH;
22615  if (!strcmp(&filebasename[strlen(filebasename) - 4], ".ele")) {
22616  filebasename[strlen(filebasename) - 4] = '\0';
22617  //object = tetgenbehavior::MESH;
22618  }
22619  bool hole_mesh_loaded = false;
22620  tetgenio io;
22621  if (io.load_node(filebasename)) {
22622  if (io.load_tet(filebasename)) {
22623  hole_mesh_loaded = true;
22624  }
22625  }
22626  if (hole_mesh_loaded) {
22627  if (b->verbose) {
22628  printf(" Adding hole tets from the mesh %s\n", b->hole_mesh_filename);
22629  }
22630  int count = 0, hcount = 0, scount = 0;
22631  int shift = io.firstnumber > 0 ? -1 : 0;
22632  double *p1, *p2, *p3, *p4;
22633  double searchpt[3];
22634  for (i = 0; i < io.numberoftetrahedra; i++) {
22635  int *idx = &(io.tetrahedronlist[i * 4]);
22636  p1 = &(io.pointlist[(idx[0]+shift)*3]);
22637  p2 = &(io.pointlist[(idx[1]+shift)*3]);
22638  p3 = &(io.pointlist[(idx[2]+shift)*3]);
22639  p4 = &(io.pointlist[(idx[3]+shift)*3]);
22640  for (j = 0; j < 3; j++) {
22641  searchpt[j] = (p1[j]+p2[j]+p3[j]+p4[j])/4.;
22642  }
22643  // Search the point.
22644  neightet.tet = NULL;
22645  if (locate(searchpt, &neightet) != OUTSIDE) {
22646  // The tet 'neightet' contain this point.
22647  if (!infected(neightet)) {
22648  infect(neightet);
22649  tetarray->newindex((void **) &parytet);
22650  *parytet = neightet;
22651  count++;
22652  // Add its adjacent tet if it is not protected.
22653  if (!issubface(neightet)) {
22654  decode(neightet.tet[neightet.ver & 3], tetloop);
22655  if (!infected(tetloop)) {
22656  infect(tetloop);
22657  if (ishulltet(tetloop)) {
22658  hullarray->newindex((void **) &parytet);
22659  hcount++;
22660  } else {
22661  tetarray->newindex((void **) &parytet);
22662  count++;
22663  }
22664  *parytet = tetloop;
22665  }
22666  }
22667  else {
22668  // It is protected. Check if its adjacent tet is a hull tet.
22669  decode(neightet.tet[neightet.ver & 3], tetloop);
22670  if (ishulltet(tetloop)) {
22671  // It is hull tet, add it into the list. Moreover, the subface
22672  // is dead, i.e., both sides are in exterior.
22673  if (!infected(tetloop)) {
22674  infect(tetloop);
22675  hullarray->newindex((void **) &parytet);
22676  *parytet = tetloop;
22677  hcount++;
22678  }
22679  }
22680  if (infected(tetloop)) {
22681  // Both sides of this subface are in exterior.
22682  tspivot(neightet, checksh);
22683  sinfect(checksh); // Only queue it once.
22684  subfacstack->newindex((void **) &parysh);
22685  *parysh = checksh;
22686  scount++;
22687  }
22688  }
22689  }
22690  }
22691  } // i
22692  if (b->verbose) {
22693  printf(" Added %d hole tets, %d hull tet, %d hole subfaces\n",
22694  count, hcount, scount);
22695  }
22696  } // if (hole_mesh_loaded)
22697  }
22698 
22699  if (b->regionattrib && (in->numberofregions > 0)) { // -A option.
22700  // Record the tetrahedra that contains the region points for assigning
22701  // region attributes after the holes have been carved.
22702  regiontets = new triface[in->numberofregions];
22703  // Mark as marktested any tetrahedra inside volume regions.
22704  for (i = 0; i < 5 * in->numberofregions; i += 5) {
22705  // Search a tet containing the i-th region point.
22706  neightet.tet = NULL;
22707  randomsample(&(in->regionlist[i]), &neightet);
22708  if (locate(&(in->regionlist[i]), &neightet) != OUTSIDE) {
22709  regiontets[i/5] = neightet;
22710  } else {
22711  if (!b->quiet) {
22712  printf("Warning: The %d-th region point ", i/5+1);
22713  printf("lies outside the convex hull.\n");
22714  }
22715  regiontets[i/5].tet = NULL;
22716  }
22717  }
22718  }
22719 
22720  // Collect all exterior tets (in concave place and in holes).
22721  for (i = 0; i < tetarray->objects; i++) {
22722  parytet = (triface *) fastlookup(tetarray, i);
22723  j = (parytet->ver & 3); // j is the current face number.
22724  // Check the other three adjacent tets.
22725  for (k = 1; k < 4; k++) {
22726  decode(parytet->tet[(j + k) % 4], neightet);
22727  // neightet may be a hull tet.
22728  if (!infected(neightet)) {
22729  // Is neightet protected by a subface.
22730  if (!issubface(neightet)) {
22731  // Not proected. Collect it. (It must not be a hull tet).
22732  infect(neightet);
22733  tetarray->newindex((void **) &parytet1);
22734  *parytet1 = neightet;
22735  } else {
22736  // Protected. Check if it is a hull tet.
22737  if (ishulltet(neightet)) {
22738  // A hull tet. Collect it.
22739  infect(neightet);
22740  hullarray->newindex((void **) &parytet1);
22741  *parytet1 = neightet;
22742  // Both sides of this subface are exterior.
22743  tspivot(neightet, checksh);
22744  // Queue this subface (to be deleted later).
22745  sinfect(checksh); // Only queue it once.
22746  subfacstack->newindex((void **) &parysh);
22747  *parysh = checksh;
22748  }
22749  }
22750  } else {
22751  // Both sides of this face are in exterior.
22752  // If there is a subface. It should be collected.
22753  if (issubface(neightet)) {
22754  tspivot(neightet, checksh);
22755  if (!sinfected(checksh)) {
22756  sinfect(checksh);
22757  subfacstack->newindex((void **) &parysh);
22758  *parysh = checksh;
22759  }
22760  }
22761  }
22762  } // j, k
22763  } // i
22764 
22765  if (b->regionattrib && (in->numberofregions > 0)) {
22766  // Re-check saved region tets to see if they lie outside.
22767  for (i = 0; i < in->numberofregions; i++) {
22768  if (infected(regiontets[i])) {
22769  if (b->verbose) {
22770  printf("Warning: The %d-th region point ", i+1);
22771  printf("lies in the exterior of the domain.\n");
22772  }
22773  regiontets[i].tet = NULL;
22774  }
22775  }
22776  }
22777 
22778  // Collect vertices which point to infected tets. These vertices
22779  // may get deleted after the removal of exterior tets.
22780  // If -Y1 option is used, collect all Steiner points for removal.
22781  // The lists 'cavetetvertlist' and 'subvertstack' are re-used.
22782  points->traversalinit();
22783  ptloop = pointtraverse();
22784  while (ptloop != NULL) {
22785  if ((pointtype(ptloop) != UNUSEDVERTEX) &&
22786  (pointtype(ptloop) != DUPLICATEDVERTEX)) {
22787  decode(point2tet(ptloop), neightet);
22788  if (infected(neightet)) {
22789  cavetetvertlist->newindex((void **) &parypt);
22790  *parypt = ptloop;
22791  }
22792  if (b->nobisect && (b->supsteiner_level > 0)) { // -Y/1
22793  // Queue it if it is a Steiner point.
22794  if (pointmark(ptloop) >
22795  (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
22796  subvertstack->newindex((void **) &parypt);
22797  *parypt = ptloop;
22798  }
22799  }
22800  }
22801  ptloop = pointtraverse();
22802  }
22803 
22804  if (!b->convex && (tetarray->objects > 0l)) { // No -c option.
22805  // Remove exterior tets. Hull tets are updated.
22806  arraypool *newhullfacearray;
22807  triface hulltet, casface;
22808  face segloop, *paryseg;
22809  point pa, pb, pc;
22810  long delsegcount = 0l;
22811 
22812  // Collect segments which point to infected tets. Some segments
22813  // may get deleted after the removal of exterior tets.
22814  subsegs->traversalinit();
22815  segloop.sh = shellfacetraverse(subsegs);
22816  while (segloop.sh != NULL) {
22817  sstpivot1(segloop, neightet);
22818  if (infected(neightet)) {
22819  subsegstack->newindex((void **) &paryseg);
22820  *paryseg = segloop;
22821  }
22822  segloop.sh = shellfacetraverse(subsegs);
22823  }
22824 
22825  newhullfacearray = new arraypool(sizeof(triface), 10);
22826 
22827  // Create and save new hull tets.
22828  for (i = 0; i < tetarray->objects; i++) {
22829  parytet = (triface *) fastlookup(tetarray, i);
22830  for (j = 0; j < 4; j++) {
22831  decode(parytet->tet[j], tetloop);
22832  if (!infected(tetloop)) {
22833  // Found a new hull face (must be a subface).
22834  tspivot(tetloop, checksh);
22835  maketetrahedron(&hulltet);
22836  pa = org(tetloop);
22837  pb = dest(tetloop);
22838  pc = apex(tetloop);
22839  setvertices(hulltet, pb, pa, pc, dummypoint);
22840  bond(tetloop, hulltet);
22841  // Update the subface-to-tet map.
22842  sesymself(checksh);
22843  tsbond(hulltet, checksh);
22844  // Update the segment-to-tet map.
22845  for (k = 0; k < 3; k++) {
22846  if (issubseg(tetloop)) {
22847  tsspivot1(tetloop, checkseg);
22848  tssbond1(hulltet, checkseg);
22849  sstbond1(checkseg, hulltet);
22850  }
22851  enextself(tetloop);
22852  eprevself(hulltet);
22853  }
22854  // Update the point-to-tet map.
22855  setpoint2tet(pa, (tetrahedron) tetloop.tet);
22856  setpoint2tet(pb, (tetrahedron) tetloop.tet);
22857  setpoint2tet(pc, (tetrahedron) tetloop.tet);
22858  // Save the exterior tet at this hull face. It still holds pointer
22859  // to the adjacent interior tet. Use it to connect new hull tets.
22860  newhullfacearray->newindex((void **) &parytet1);
22861  parytet1->tet = parytet->tet;
22862  parytet1->ver = j;
22863  } // if (!infected(tetloop))
22864  } // j
22865  } // i
22866 
22867  // Connect new hull tets.
22868  for (i = 0; i < newhullfacearray->objects; i++) {
22869  parytet = (triface *) fastlookup(newhullfacearray, i);
22870  fsym(*parytet, neightet);
22871  // Get the new hull tet.
22872  fsym(neightet, hulltet);
22873  for (j = 0; j < 3; j++) {
22874  esym(hulltet, casface);
22875  if (casface.tet[casface.ver & 3] == NULL) {
22876  // Since the boundary of the domain may not be a manifold, we
22877  // find the adjacent hull face by traversing the tets in the
22878  // exterior (which are all infected tets).
22879  neightet = *parytet;
22880  while (1) {
22881  fnextself(neightet);
22882  if (!infected(neightet)) break;
22883  }
22884  if (!ishulltet(neightet)) {
22885  // An interior tet. Get the new hull tet.
22886  fsymself(neightet);
22887  esymself(neightet);
22888  }
22889  // Bond them together.
22890  bond(casface, neightet);
22891  }
22892  enextself(hulltet);
22893  enextself(*parytet);
22894  } // j
22895  } // i
22896 
22897  if (subfacstack->objects > 0l) {
22898  // Remove all subfaces which do not attach to any tetrahedron.
22899  // Segments which are not attached to any subfaces and tets
22900  // are deleted too.
22901  face casingout, casingin;
22902 
22903  for (i = 0; i < subfacstack->objects; i++) {
22904  parysh = (face *) fastlookup(subfacstack, i);
22905  if (i == 0) {
22906  if (b->verbose) {
22907  printf("Warning: Removed an exterior face (%d, %d, %d) #%d\n",
22908  pointmark(sorg(*parysh)), pointmark(sdest(*parysh)),
22909  pointmark(sapex(*parysh)), shellmark(*parysh));
22910  }
22911  }
22912  // Dissolve this subface from face links.
22913  for (j = 0; j < 3; j++) {
22914  spivot(*parysh, casingout);
22915  sspivot(*parysh, checkseg);
22916  if (casingout.sh != NULL) {
22917  casingin = casingout;
22918  while (1) {
22919  spivot(casingin, checksh);
22920  if (checksh.sh == parysh->sh) break;
22921  casingin = checksh;
22922  }
22923  if (casingin.sh != casingout.sh) {
22924  // Update the link: ... -> casingin -> casingout ->...
22925  sbond1(casingin, casingout);
22926  } else {
22927  // Only one subface at this edge is left.
22928  sdissolve(casingout);
22929  }
22930  if (checkseg.sh != NULL) {
22931  // Make sure the segment does not connect to a dead one.
22932  ssbond(casingout, checkseg);
22933  }
22934  } else {
22935  if (checkseg.sh != NULL) {
22936  //if (checkseg.sh[3] != NULL) {
22937  if (delsegcount == 0) {
22938  if (b->verbose) {
22939  printf("Warning: Removed an exterior segment (%d, %d) #%d\n",
22940  pointmark(sorg(checkseg)), pointmark(sdest(checkseg)),
22941  shellmark(checkseg));
22942  }
22943  }
22944  shellfacedealloc(subsegs, checkseg.sh);
22945  delsegcount++;
22946  }
22947  }
22948  senextself(*parysh);
22949  } // j
22950  // Delete this subface.
22951  shellfacedealloc(subfaces, parysh->sh);
22952  } // i
22953  if (b->verbose) {
22954  printf(" Deleted %ld subfaces.\n", subfacstack->objects);
22955  }
22956  subfacstack->restart();
22957  } // if (subfacstack->objects > 0l)
22958 
22959  if (subsegstack->objects > 0l) {
22960  for (i = 0; i < subsegstack->objects; i++) {
22961  paryseg = (face *) fastlookup(subsegstack, i);
22962  if (paryseg->sh && (paryseg->sh[3] != NULL)) {
22963  sstpivot1(*paryseg, neightet);
22964  if (infected(neightet)) {
22965  if (b->verbose) {
22966  printf("Warning: Removed an exterior segment (%d, %d) #%d\n",
22967  pointmark(sorg(*paryseg)), pointmark(sdest(*paryseg)),
22968  shellmark(*paryseg));
22969  }
22970  shellfacedealloc(subsegs, paryseg->sh);
22971  delsegcount++;
22972  }
22973  }
22974  }
22975  subsegstack->restart();
22976  } // if (subsegstack->objects > 0l)
22977 
22978  if (delsegcount > 0) {
22979  if (b->verbose) {
22980  printf(" Deleted %ld segments.\n", delsegcount);
22981  }
22982  }
22983 
22984  if (cavetetvertlist->objects > 0l) {
22985  // Some vertices may lie in exterior. Marke them as UNUSEDVERTEX.
22986  long delvertcount = unuverts;
22987  long delsteinercount = 0l;
22988 
22989  for (i = 0; i < cavetetvertlist->objects; i++) {
22990  parypt = (point *) fastlookup(cavetetvertlist, i);
22991  decode(point2tet(*parypt), neightet);
22992  if (infected(neightet)) {
22993  // Found an exterior vertex.
22994  if (pointmark(*parypt) >
22995  (in->numberofpoints - (in->firstnumber ? 0 : 1))) {
22996  // A Steiner point.
22997  if (pointtype(*parypt) == FREESEGVERTEX) {
22998  st_segref_count--;
22999  } else if (pointtype(*parypt) == FREEFACETVERTEX) {
23000  st_facref_count--;
23001  } else {
23002  st_volref_count--;
23003  }
23004  delsteinercount++;
23005  if (steinerleft > 0) steinerleft++;
23006  }
23007  setpointtype(*parypt, UNUSEDVERTEX);
23008  unuverts++;
23009  }
23010  }
23011 
23012  if (b->verbose) {
23013  if (unuverts > delvertcount) {
23014  if (delsteinercount > 0l) {
23015  if (unuverts > (delvertcount + delsteinercount)) {
23016  printf(" Removed %ld exterior input vertices.\n",
23017  unuverts - delvertcount - delsteinercount);
23018  }
23019  printf(" Removed %ld exterior Steiner vertices.\n",
23020  delsteinercount);
23021  } else {
23022  printf(" Removed %ld exterior input vertices.\n",
23023  unuverts - delvertcount);
23024  }
23025  }
23026  }
23027  cavetetvertlist->restart();
23028  // Comment: 'subvertstack' will be cleaned in routine
23029  // suppresssteinerpoints().
23030  } // if (cavetetvertlist->objects > 0l)
23031 
23032  // Update the hull size.
23033  hullsize += (newhullfacearray->objects - hullarray->objects);
23034 
23035  // Delete all exterior tets and old hull tets.
23036  for (i = 0; i < tetarray->objects; i++) {
23037  parytet = (triface *) fastlookup(tetarray, i);
23038  tetrahedrondealloc(parytet->tet);
23039  }
23040  tetarray->restart();
23041 
23042  for (i = 0; i < hullarray->objects; i++) {
23043  parytet = (triface *) fastlookup(hullarray, i);
23044  tetrahedrondealloc(parytet->tet);
23045  }
23046  hullarray->restart();
23047 
23048  delete newhullfacearray;
23049  } // if (!b->convex && (tetarray->objects > 0l))
23050 
23051  if (b->convex && (tetarray->objects > 0l)) { // With -c option
23052  // In this case, all exterior tets get a region marker '-1'.
23053  int attrnum = numelemattrib - 1;
23054 
23055  for (i = 0; i < tetarray->objects; i++) {
23056  parytet = (triface *) fastlookup(tetarray, i);
23057  setelemattribute(parytet->tet, attrnum, -1);
23058  }
23059  tetarray->restart();
23060 
23061  for (i = 0; i < hullarray->objects; i++) {
23062  parytet = (triface *) fastlookup(hullarray, i);
23063  uninfect(*parytet);
23064  }
23065  hullarray->restart();
23066 
23067  if (subfacstack->objects > 0l) {
23068  for (i = 0; i < subfacstack->objects; i++) {
23069  parysh = (face *) fastlookup(subfacstack, i);
23070  suninfect(*parysh);
23071  }
23072  subfacstack->restart();
23073  }
23074 
23075  if (cavetetvertlist->objects > 0l) {
23076  cavetetvertlist->restart();
23077  }
23078  } // if (b->convex && (tetarray->objects > 0l))
23079 
23080  if (b->regionattrib) { // With -A option.
23081  if (!b->quiet) {
23082  printf("Spreading region attributes.\n");
23083  }
23084  REAL volume;
23085  int attr, maxattr = 0; // Choose a small number here.
23086  int attrnum = numelemattrib - 1;
23087  // Comment: The element region marker is at the end of the list of
23088  // the element attributes.
23089  int regioncount = 0;
23090 
23091  // If has user-defined region attributes.
23092  if (in->numberofregions > 0) {
23093  // Spread region attributes.
23094  for (i = 0; i < 5 * in->numberofregions; i += 5) {
23095  if (regiontets[i/5].tet != NULL) {
23096  attr = (int) in->regionlist[i + 3];
23097  if (attr > maxattr) {
23098  maxattr = attr;
23099  }
23100  volume = in->regionlist[i + 4];
23101  tetarray->restart(); // Re-use this array.
23102  infect(regiontets[i/5]);
23103  tetarray->newindex((void **) &parytet);
23104  *parytet = regiontets[i/5];
23105  // Collect and set attrs for all tets of this region.
23106  for (j = 0; j < tetarray->objects; j++) {
23107  parytet = (triface *) fastlookup(tetarray, j);
23108  tetloop = *parytet;
23109  setelemattribute(tetloop.tet, attrnum, attr);
23110  if (b->varvolume) { // If has -a option.
23111  setvolumebound(tetloop.tet, volume);
23112  }
23113  for (k = 0; k < 4; k++) {
23114  decode(tetloop.tet[k], neightet);
23115  // Is the adjacent already checked?
23116  if (!infected(neightet)) {
23117  // Is this side protected by a subface?
23118  if (!issubface(neightet)) {
23119  infect(neightet);
23120  tetarray->newindex((void **) &parytet);
23121  *parytet = neightet;
23122  }
23123  }
23124  } // k
23125  } // j
23126  regioncount++;
23127  } // if (regiontets[i/5].tet != NULL)
23128  } // i
23129  }
23130 
23131  // Set attributes for all tetrahedra.
23132  attr = maxattr + 1;
23133  tetrahedrons->traversalinit();
23134  tetloop.tet = tetrahedrontraverse();
23135  while (tetloop.tet != (tetrahedron *) NULL) {
23136  if (!infected(tetloop)) {
23137  // An unmarked region.
23138  tetarray->restart(); // Re-use this array.
23139  infect(tetloop);
23140  tetarray->newindex((void **) &parytet);
23141  *parytet = tetloop;
23142  // Find and mark all tets.
23143  for (j = 0; j < tetarray->objects; j++) {
23144  parytet = (triface *) fastlookup(tetarray, j);
23145  tetloop = *parytet;
23146  setelemattribute(tetloop.tet, attrnum, attr);
23147  for (k = 0; k < 4; k++) {
23148  decode(tetloop.tet[k], neightet);
23149  // Is the adjacent tet already checked?
23150  if (!infected(neightet)) {
23151  // Is this side protected by a subface?
23152  if (!issubface(neightet)) {
23153  infect(neightet);
23154  tetarray->newindex((void **) &parytet);
23155  *parytet = neightet;
23156  }
23157  }
23158  } // k
23159  } // j
23160  attr++; // Increase the attribute.
23161  regioncount++;
23162  }
23163  tetloop.tet = tetrahedrontraverse();
23164  }
23165  // Until here, every tet has a region attribute.
23166 
23167  // Uninfect processed tets.
23168  tetrahedrons->traversalinit();
23169  tetloop.tet = tetrahedrontraverse();
23170  while (tetloop.tet != (tetrahedron *) NULL) {
23171  uninfect(tetloop);
23172  tetloop.tet = tetrahedrontraverse();
23173  }
23174 
23175  if (b->verbose) {
23176  //assert(regioncount > 0);
23177  if (regioncount > 1) {
23178  printf(" Found %d subdomains.\n", regioncount);
23179  } else {
23180  printf(" Found %d domain.\n", regioncount);
23181  }
23182  }
23183  } // if (b->regionattrib)
23184 
23185  if (regiontets != NULL) {
23186  delete [] regiontets;
23187  }
23188  delete tetarray;
23189  delete hullarray;
23190 
23191  if (!b->convex) { // No -c option
23192  // The mesh is non-convex now.
23193  nonconvex = 1;
23194 
23195  // Push all hull tets into 'flipstack'.
23196  tetrahedrons->traversalinit();
23197  tetloop.ver = 11; // The face opposite to dummypoint.
23198  tetloop.tet = alltetrahedrontraverse();
23199  while (tetloop.tet != (tetrahedron *) NULL) {
23200  if ((point) tetloop.tet[7] == dummypoint) {
23201  fsym(tetloop, neightet);
23202  flippush(flipstack, &neightet);
23203  }
23204  tetloop.tet = alltetrahedrontraverse();
23205  }
23206 
23207  flipconstraints fc;
23208  fc.enqflag = 2;
23209  long sliver_peel_count = lawsonflip3d(&fc);
23210 
23211  if (sliver_peel_count > 0l) {
23212  if (b->verbose) {
23213  printf(" Removed %ld hull slivers.\n", sliver_peel_count);
23214  }
23215  }
23216  unflipqueue->restart();
23217  } // if (!b->convex)
23218 }
23219 
23220 // [2018-07-30]
23221 // Search a face with given indices (i,j,k).
23222 // This function is only called when the default fast search fails.
23223 // It is possible when there are non-manifold edges on the hull.
23224 // On finish, tetloop return this face if it exists, otherwise, return 0.
23225 int tetgenmesh::search_face(point pi, point pj, point pk, triface &tetloop)
23226 {
23227  pinfect(pi);
23228  pinfect(pj);
23229  pinfect(pk);
23230 
23231  int t1ver;
23232  triface t, t1;
23233  point *pts, toppo;
23234  int pcount = 0;
23235 
23236  t.ver = t1.ver = 0;
23237  tetrahedrons->traversalinit();
23238  t.tet = tetrahedrontraverse();
23239  while (t.tet != NULL) {
23240  pts = (point *) t.tet;
23241  pcount = 0;
23242  if (pinfected(pts[4])) pcount++;
23243  if (pinfected(pts[5])) pcount++;
23244  if (pinfected(pts[6])) pcount++;
23245  if (pinfected(pts[7])) pcount++;
23246 
23247  if (pcount == 3) {
23248  // Found a tet containing this face.
23249  for (t.ver = 0; t.ver < 4; t.ver++) {
23250  toppo = oppo(t);
23251  if (!pinfected(toppo)) break;
23252  }
23253  int ii;
23254  for (ii = 0; ii < 3; ii++) {
23255  if (org(t) == pi) break;
23256  enextself(t);
23257  }
23258  if (dest(t) == pj) {
23259  } else {
23260  eprevself(t);
23261  fsymself(t);
23262  }
23263  break;
23264  }
23265  t.tet = tetrahedrontraverse();
23266  }
23267 
23268  puninfect(pi);
23269  puninfect(pj);
23270  puninfect(pk);
23271 
23272  if (t.tet != NULL) {
23273  tetloop = t;
23274  return 1;
23275  } else {
23276  return 0;
23277  }
23278 }
23279 
23280 int tetgenmesh::search_edge(point p0, point p1, triface &tetloop)
23281 {
23282  triface t;
23283  int ii;
23284 
23285  tetrahedrons->traversalinit();
23286  t.tet = tetrahedrontraverse();
23287  while (t.tet != NULL) {
23288  for (ii = 0; ii < 6; ii++) {
23289  t.ver = edge2ver[ii];
23290  if (((org(t) == p0) && (dest(t) == p1)) ||
23291  ((org(t) == p1) && (dest(t) == p0))) {
23292  // Found the tet.
23293  tetloop = t;
23294  return 1;
23295  }
23296  }
23297  t.tet = tetrahedrontraverse();
23298  }
23299 
23300  tetloop.tet = NULL;
23301  return 0;
23302 }
23303 
23305 // //
23306 // reconstructmesh() Reconstruct a tetrahedral mesh. //
23307 // //
23309 
23310 void tetgenmesh::reconstructmesh()
23311 {
23312  tetrahedron *ver2tetarray;
23313  point *idx2verlist;
23314  triface tetloop, checktet, prevchktet;
23315  triface hulltet, face1, face2;
23316  tetrahedron tptr;
23317  face subloop, neighsh, nextsh;
23318  face segloop;
23319  shellface sptr;
23320  point p[4], q[3];
23321  REAL ori, attrib, volume;
23322  REAL cosang_tol, cosang;
23323  REAL n1[3], n2[3];
23324  int eextras, marker = 0;
23325  int bondflag;
23326  int t1ver;
23327  int idx, i, j, k;
23328 
23329  if (!b->quiet) {
23330  printf("Reconstructing mesh ...\n");
23331  }
23332 
23333  if (b->convex) { // -c option.
23334  // Assume the mesh is convex. Exterior tets have region attribute -1.
23335  if (!(in->numberoftetrahedronattributes > 0)) {
23336  terminatetetgen(this, 2);
23337  }
23338  } else {
23339  // Assume the mesh is non-convex.
23340  nonconvex = 1;
23341  }
23342 
23343  // Create a map from indices to vertices.
23344  makeindex2pointmap(idx2verlist);
23345  // 'idx2verlist' has length 'in->numberofpoints + 1'.
23346  if (in->firstnumber == 1) {
23347  idx2verlist[0] = dummypoint; // Let 0th-entry be dummypoint.
23348  }
23349 
23350  // Allocate an array that maps each vertex to its adjacent tets.
23351  ver2tetarray = new tetrahedron[in->numberofpoints + 1];
23352  unuverts = in->numberofpoints; // All vertices are unused yet.
23353  //for (i = 0; i < in->numberofpoints + 1; i++) {
23354  for (i = in->firstnumber; i < in->numberofpoints + in->firstnumber; i++) {
23355  ver2tetarray[i] = NULL;
23356  }
23357 
23358  // Create the tetrahedra and connect those that share a common face.
23359  for (i = 0; i < in->numberoftetrahedra; i++) {
23360  // Get the four vertices.
23361  idx = i * in->numberofcorners;
23362  for (j = 0; j < 4; j++) {
23363  p[j] = idx2verlist[in->tetrahedronlist[idx++]];
23364  if (pointtype(p[j]) == UNUSEDVERTEX) {
23365  setpointtype(p[j], VOLVERTEX); // initial type.
23366  unuverts--;
23367  }
23368  }
23369  // Check the orientation.
23370  ori = orient3d(p[0], p[1], p[2], p[3]);
23371  if (ori > 0.0) {
23372  // Swap the first two vertices.
23373  q[0] = p[0]; p[0] = p[1]; p[1] = q[0];
23374  } else if (ori == 0.0) {
23375  if (!b->quiet) {
23376  printf("Warning: Tet #%d is degenerate.\n", i + in->firstnumber);
23377  }
23378  }
23379  // Create a new tetrahedron.
23380  maketetrahedron(&tetloop); // tetloop.ver = 11.
23381  setvertices(tetloop, p[0], p[1], p[2], p[3]);
23382  // Set element attributes if they exist.
23383  for (j = 0; j < in->numberoftetrahedronattributes; j++) {
23384  idx = i * in->numberoftetrahedronattributes;
23385  attrib = in->tetrahedronattributelist[idx + j];
23386  setelemattribute(tetloop.tet, j, attrib);
23387  }
23388  // If -a switch is used (with no number follows) Set a volume
23389  // constraint if it exists.
23390  if (b->varvolume) {
23391  if (in->tetrahedronvolumelist != (REAL *) NULL) {
23392  volume = in->tetrahedronvolumelist[i];
23393  } else {
23394  volume = -1.0;
23395  }
23396  setvolumebound(tetloop.tet, volume);
23397  }
23398  // Try connecting this tet to others that share the common faces.
23399  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
23400  p[3] = oppo(tetloop);
23401  // Look for other tets having this vertex.
23402  idx = pointmark(p[3]);
23403  tptr = ver2tetarray[idx];
23404  // Link the current tet to the next one in the stack.
23405  tetloop.tet[8 + tetloop.ver] = tptr;
23406  // Push the current tet onto the stack.
23407  ver2tetarray[idx] = encode(tetloop);
23408  decode(tptr, checktet);
23409  if (checktet.tet != NULL) {
23410  p[0] = org(tetloop); // a
23411  p[1] = dest(tetloop); // b
23412  p[2] = apex(tetloop); // c
23413  prevchktet = tetloop;
23414  do {
23415  q[0] = org(checktet); // a'
23416  q[1] = dest(checktet); // b'
23417  q[2] = apex(checktet); // c'
23418  // Check the three faces at 'd' in 'checktet'.
23419  bondflag = 0;
23420  for (j = 0; j < 3; j++) {
23421  // Go to the face [b',a',d], or [c',b',d], or [a',c',d].
23422  esym(checktet, face2);
23423  if (face2.tet[face2.ver & 3] == NULL) {
23424  k = ((j + 1) % 3);
23425  if (q[k] == p[0]) { // b', c', a' = a
23426  if (q[j] == p[1]) { // a', b', c' = b
23427  // [#,#,d] is matched to [b,a,d].
23428  esym(tetloop, face1);
23429  bond(face1, face2);
23430  bondflag++;
23431  }
23432  }
23433  if (q[k] == p[1]) { // b',c',a' = b
23434  if (q[j] == p[2]) { // a',b',c' = c
23435  // [#,#,d] is matched to [c,b,d].
23436  enext(tetloop, face1);
23437  esymself(face1);
23438  bond(face1, face2);
23439  bondflag++;
23440  }
23441  }
23442  if (q[k] == p[2]) { // b',c',a' = c
23443  if (q[j] == p[0]) { // a',b',c' = a
23444  // [#,#,d] is matched to [a,c,d].
23445  eprev(tetloop, face1);
23446  esymself(face1);
23447  bond(face1, face2);
23448  bondflag++;
23449  }
23450  }
23451  } else {
23452  bondflag++;
23453  }
23454  enextself(checktet);
23455  } // j
23456  // Go to the next tet in the link.
23457  tptr = checktet.tet[8 + checktet.ver];
23458  if (bondflag == 3) {
23459  // All three faces at d in 'checktet' have been connected.
23460  // It can be removed from the link.
23461  prevchktet.tet[8 + prevchktet.ver] = tptr;
23462  } else {
23463  // Bakup the previous tet in the link.
23464  prevchktet = checktet;
23465  }
23466  decode(tptr, checktet);
23467  } while (checktet.tet != NULL);
23468  } // if (checktet.tet != NULL)
23469  } // for (tetloop.ver = 0; ...
23470  } // i
23471 
23472  // Remember a tet of the mesh.
23473  recenttet = tetloop;
23474 
23475  // Create hull tets, create the point-to-tet map, and clean up the
23476  // temporary spaces used in each tet.
23477  hullsize = tetrahedrons->items;
23478 
23479  tetrahedrons->traversalinit();
23480  tetloop.tet = tetrahedrontraverse();
23481  while (tetloop.tet != (tetrahedron *) NULL) {
23482  tptr = encode(tetloop);
23483  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
23484  if (tetloop.tet[tetloop.ver] == NULL) {
23485  // Create a hull tet.
23486  maketetrahedron(&hulltet);
23487  p[0] = org(tetloop);
23488  p[1] = dest(tetloop);
23489  p[2] = apex(tetloop);
23490  setvertices(hulltet, p[1], p[0], p[2], dummypoint);
23491  bond(tetloop, hulltet);
23492  // Try connecting this to others that share common hull edges.
23493  for (j = 0; j < 3; j++) {
23494  fsym(hulltet, face2);
23495  while (1) {
23496  if (face2.tet == NULL) break;
23497  esymself(face2);
23498  if (apex(face2) == dummypoint) break;
23499  fsymself(face2);
23500  }
23501  if (face2.tet != NULL) {
23502  // Found an adjacent hull tet.
23503  esym(hulltet, face1);
23504  bond(face1, face2);
23505  }
23506  enextself(hulltet);
23507  }
23508  }
23509  // Create the point-to-tet map.
23510  setpoint2tet((point) (tetloop.tet[4 + tetloop.ver]), tptr);
23511  // Clean the temporary used space.
23512  tetloop.tet[8 + tetloop.ver] = NULL;
23513  }
23514  tetloop.tet = tetrahedrontraverse();
23515  }
23516 
23517  hullsize = tetrahedrons->items - hullsize;
23518 
23519  // Subfaces will be inserted into the mesh.
23520  if (in->trifacelist != NULL) {
23521  // A .face file is given. It may contain boundary faces. Insert them.
23522  for (i = 0; i < in->numberoftrifaces; i++) {
23523  // Is it a subface?
23524  if (in->trifacemarkerlist != NULL) {
23525  marker = in->trifacemarkerlist[i];
23526  } else {
23527  // Face markers are not available. Assume all of them are subfaces.
23528  marker = -1; // The default marker.
23529  }
23530  if (marker != 0) {
23531  idx = i * 3;
23532  for (j = 0; j < 3; j++) {
23533  p[j] = idx2verlist[in->trifacelist[idx++]];
23534  }
23535  // Search the subface.
23536  bondflag = 0;
23537  neighsh.sh = NULL;
23538  // Make sure all vertices are in the mesh. Avoid crash.
23539  for (j = 0; j < 3; j++) {
23540  decode(point2tet(p[j]), checktet);
23541  if (checktet.tet == NULL) break;
23542  }
23543  if ((j == 3) && getedge(p[0], p[1], &checktet)) {
23544  tetloop = checktet;
23545  q[2] = apex(checktet);
23546  while (1) {
23547  if (apex(tetloop) == p[2]) {
23548  // Found the face.
23549  // Check if there exist a subface already?
23550  tspivot(tetloop, neighsh);
23551  if (neighsh.sh != NULL) {
23552  // Found a duplicated subface.
23553  // This happens when the mesh was generated by other mesher.
23554  bondflag = 0;
23555  } else {
23556  bondflag = 1;
23557  }
23558  break;
23559  }
23560  fnextself(tetloop);
23561  if (apex(tetloop) == q[2]) break;
23562  }
23563  }
23564  if (!bondflag) {
23565  if (neighsh.sh == NULL) {
23566  if (b->verbose > 1) {
23567  printf("Warning: Searching subface #%d [%d,%d,%d] mark=%d.\n",
23568  i + in->firstnumber, pointmark(p[0]), pointmark(p[1]),
23569  pointmark(p[2]), marker);
23570  }
23571  // Search it globally.
23572  if (search_face(p[0], p[1], p[2], tetloop)) {
23573  bondflag = 1;
23574  }
23575  }
23576  }
23577  if (bondflag) {
23578  // Create a new subface.
23579  makeshellface(subfaces, &subloop);
23580  setshvertices(subloop, p[0], p[1], p[2]);
23581  // Create the point-to-subface map.
23582  sptr = sencode(subloop);
23583  for (j = 0; j < 3; j++) {
23584  setpointtype(p[j], FACETVERTEX); // initial type.
23585  setpoint2sh(p[j], sptr);
23586  }
23587  setshellmark(subloop, marker);
23588  // Insert the subface into the mesh.
23589  tsbond(tetloop, subloop);
23590  fsymself(tetloop);
23591  sesymself(subloop);
23592  tsbond(tetloop, subloop);
23593  } else {
23594  if (neighsh.sh != NULL) {
23595  // The subface already exists. Only set its mark.
23596  setshellmark(neighsh, marker);
23597  } else {
23598  if (!b->quiet) {
23599  printf("Warning: Subface #%d [%d,%d,%d] mark=%d is not found.\n",
23600  i + in->firstnumber, pointmark(p[0]), pointmark(p[1]),
23601  pointmark(p[2]), marker);
23602  }
23603  }
23604  } // if (bondflag)
23605  } // if (marker != 0)
23606  } // i
23607  } // if (in->trifacelist)
23608 
23609  // Indentify subfaces from the mesh.
23610  // Create subfaces for hull faces (if they're not subface yet) and
23611  // interior faces which separate two different materials.
23612  eextras = in->numberoftetrahedronattributes;
23613  tetrahedrons->traversalinit();
23614  tetloop.tet = tetrahedrontraverse();
23615  while (tetloop.tet != (tetrahedron *) NULL) {
23616  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
23617  tspivot(tetloop, neighsh);
23618  if (neighsh.sh == NULL) {
23619  bondflag = 0;
23620  fsym(tetloop, checktet);
23621  if (ishulltet(checktet)) {
23622  // A hull face.
23623  if (!b->convex) {
23624  bondflag = 1; // Insert a hull subface.
23625  }
23626  } else {
23627  if (eextras > 0) {
23628  if (elemattribute(tetloop.tet, eextras - 1) !=
23629  elemattribute(checktet.tet, eextras - 1)) {
23630  bondflag = 1; // Insert an interior interface.
23631  }
23632  }
23633  }
23634  if (bondflag) {
23635  // Create a new subface.
23636  makeshellface(subfaces, &subloop);
23637  p[0] = org(tetloop);
23638  p[1] = dest(tetloop);
23639  p[2] = apex(tetloop);
23640  setshvertices(subloop, p[0], p[1], p[2]);
23641  // Create the point-to-subface map.
23642  sptr = sencode(subloop);
23643  for (j = 0; j < 3; j++) {
23644  setpointtype(p[j], FACETVERTEX); // initial type.
23645  setpoint2sh(p[j], sptr);
23646  }
23647  setshellmark(subloop, -1); // Default marker.
23648  // Insert the subface into the mesh.
23649  tsbond(tetloop, subloop);
23650  sesymself(subloop);
23651  tsbond(checktet, subloop);
23652  } // if (bondflag)
23653  } // if (neighsh.sh == NULL)
23654  }
23655  tetloop.tet = tetrahedrontraverse();
23656  }
23657 
23658  // Connect subfaces together.
23659  subfaces->traversalinit();
23660  subloop.shver = 0;
23661  subloop.sh = shellfacetraverse(subfaces);
23662  while (subloop.sh != (shellface *) NULL) {
23663  for (i = 0; i < 3; i++) {
23664  spivot(subloop, neighsh);
23665  if (neighsh.sh == NULL) {
23666  // Form a subface ring by linking all subfaces at this edge.
23667  // Traversing all faces of the tets at this edge.
23668  stpivot(subloop, tetloop);
23669  q[2] = apex(tetloop);
23670  neighsh = subloop;
23671  while (1) {
23672  fnextself(tetloop);
23673  tspivot(tetloop, nextsh);
23674  if (nextsh.sh != NULL) {
23675  // Do not connect itself.
23676  if (nextsh.sh != neighsh.sh) {
23677  // Link neighsh <= nextsh.
23678  sbond1(neighsh, nextsh);
23679  neighsh = nextsh;
23680  }
23681  }
23682  if (apex(tetloop) == q[2]) {
23683  break;
23684  }
23685  } // while (1)
23686  } // if (neighsh.sh == NULL)
23687  senextself(subloop);
23688  }
23689  subloop.sh = shellfacetraverse(subfaces);
23690  }
23691 
23692 
23693  // Segments will be introduced.
23694  if (in->edgelist != NULL) {
23695  // A .edge file is given. It may contain boundary edges. Insert them.
23696  for (i = 0; i < in->numberofedges; i++) {
23697  // Is it a segment?
23698  if (in->edgemarkerlist != NULL) {
23699  marker = in->edgemarkerlist[i];
23700  } else {
23701  // Edge markers are not available. Assume all of them are segments.
23702  marker = -1; // Default marker.
23703  }
23704  if (marker != 0) {
23705  // Insert a segment.
23706  idx = i * 2;
23707  for (j = 0; j < 2; j++) {
23708  p[j] = idx2verlist[in->edgelist[idx++]];
23709  }
23710  // Make sure all vertices are in the mesh. Avoid crash.
23711  for (j = 0; j < 2; j++) {
23712  decode(point2tet(p[j]), checktet);
23713  if (checktet.tet == NULL) break;
23714  }
23715  // Search the segment.
23716  bondflag = 0;
23717  if (j == 2) {
23718  if (getedge(p[0], p[1], &checktet)) {
23719  bondflag = 1;
23720  } else {
23721  if (b->verbose > 1) {
23722  printf("Warning: Searching segment #%d [%d,%d] mark=%d.\n",
23723  i + in->firstnumber, pointmark(p[0]), pointmark(p[1]), marker);
23724  }
23725  // Search it globally.
23726  if (search_edge(p[0], p[1], checktet)) {
23727  bondflag = 1;
23728  }
23729  }
23730  }
23731  if (bondflag > 0) {
23732  // Create a new segment.
23733  makeshellface(subsegs, &segloop);
23734  setshvertices(segloop, p[0], p[1], NULL);
23735  // Create the point-to-segment map.
23736  sptr = sencode(segloop);
23737  for (j = 0; j < 2; j++) {
23738  setpointtype(p[j], RIDGEVERTEX); // initial type.
23739  setpoint2sh(p[j], sptr);
23740  }
23741  setshellmark(segloop, marker);
23742  // Insert the segment into the mesh.
23743  tetloop = checktet;
23744  q[2] = apex(checktet);
23745  subloop.sh = NULL;
23746  while (1) {
23747  tssbond1(tetloop, segloop);
23748  tspivot(tetloop, subloop);
23749  if (subloop.sh != NULL) {
23750  ssbond1(subloop, segloop);
23751  sbond1(segloop, subloop);
23752  }
23753  fnextself(tetloop);
23754  if (apex(tetloop) == q[2]) break;
23755  } // while (1)
23756  // Remember an adjacent tet for this segment.
23757  sstbond1(segloop, tetloop);
23758  } else {
23759  if (!b->quiet) {
23760  printf("Warning: Segment #%d [%d,%d] is missing.\n",
23761  i + in->firstnumber, pointmark(p[0]), pointmark(p[1]));
23762  }
23763  }
23764  } // if (marker != 0)
23765  } // i
23766  } // if (in->edgelist)
23767 
23768  // Identify segments from the mesh.
23769  // Create segments for non-manifold edges (which are shared by more
23770  // than two subfaces), and for non-coplanar edges, i.e., two subfaces
23771  // form an dihedral angle > 'b->facet_separate_ang_tol' (degree).
23772  cosang_tol = cos(b->facet_separate_ang_tol / 180.0 * PI);
23773  subfaces->traversalinit();
23774  subloop.shver = 0;
23775  subloop.sh = shellfacetraverse(subfaces);
23776  while (subloop.sh != (shellface *) NULL) {
23777  for (i = 0; i < 3; i++) {
23778  sspivot(subloop, segloop);
23779  if (segloop.sh == NULL) {
23780  // Check if this edge is a segment.
23781  bondflag = 0;
23782  // Counter the number of subfaces at this edge.
23783  idx = 0;
23784  nextsh = subloop;
23785  while (1) {
23786  idx++;
23787  spivotself(nextsh);
23788  if (nextsh.sh == subloop.sh) break;
23789  }
23790  if (idx != 2) {
23791  // It's a non-manifold edge. Insert a segment.
23792  p[0] = sorg(subloop);
23793  p[1] = sdest(subloop);
23794  bondflag = 1;
23795  } else {
23796  spivot(subloop, neighsh);
23797  if (shellmark(subloop) != shellmark(neighsh)) {
23798  // It's an interior interface. Insert a segment.
23799  p[0] = sorg(subloop);
23800  p[1] = sdest(subloop);
23801  bondflag = 1;
23802  } else {
23803  if (!b->convex) {
23804  // Check the dihedral angle formed by the two subfaces.
23805  p[0] = sorg(subloop);
23806  p[1] = sdest(subloop);
23807  p[2] = sapex(subloop);
23808  p[3] = sapex(neighsh);
23809  facenormal(p[0], p[1], p[2], n1, 1, NULL);
23810  facenormal(p[0], p[1], p[3], n2, 1, NULL);
23811  cosang = dot(n1, n2) / (sqrt(dot(n1, n1)) * sqrt(dot(n2, n2)));
23812  // Rounding.
23813  if (cosang > 1.0) cosang = 1.0;
23814  else if (cosang < -1.0) cosang = -1.0;
23815  if (cosang > cosang_tol) {
23816  bondflag = 1;
23817  }
23818  }
23819  }
23820  }
23821  if (bondflag) {
23822  // Create a new segment.
23823  makeshellface(subsegs, &segloop);
23824  setshvertices(segloop, p[0], p[1], NULL);
23825  // Create the point-to-segment map.
23826  sptr = sencode(segloop);
23827  for (j = 0; j < 2; j++) {
23828  setpointtype(p[j], RIDGEVERTEX); // initial type.
23829  setpoint2sh(p[j], sptr);
23830  }
23831  setshellmark(segloop, -1); // Default marker.
23832  // Insert the subface into the mesh.
23833  stpivot(subloop, tetloop);
23834  q[2] = apex(tetloop);
23835  while (1) {
23836  tssbond1(tetloop, segloop);
23837  tspivot(tetloop, neighsh);
23838  if (neighsh.sh != NULL) {
23839  ssbond1(neighsh, segloop);
23840  }
23841  fnextself(tetloop);
23842  if (apex(tetloop) == q[2]) break;
23843  } // while (1)
23844  // Remember an adjacent tet for this segment.
23845  sstbond1(segloop, tetloop);
23846  sbond1(segloop, subloop);
23847  } // if (bondflag)
23848  } // if (neighsh.sh == NULL)
23849  senextself(subloop);
23850  } // i
23851  subloop.sh = shellfacetraverse(subfaces);
23852  }
23853 
23854  // Remember the number of input segments.
23855  insegments = subsegs->items;
23856 
23857  if (!b->nobisect || checkconstraints) {
23858  // Mark Steiner points on segments and facets.
23859  // - all vertices which remaining type FEACTVERTEX become
23860  // Steiner points in facets (= FREEFACERVERTEX).
23861  // - vertices on segment need to be checked.
23862  face* segperverlist;
23863  int* idx2seglist;
23864  face parentseg, nextseg;
23865  verttype vt;
23866  REAL area, len, l1, l2;
23867  int fmarker;
23868 
23869  makepoint2submap(subsegs, idx2seglist, segperverlist);
23870 
23871  points->traversalinit();
23872  point ptloop = pointtraverse();
23873  while (ptloop != NULL) {
23874  vt = pointtype(ptloop);
23875  if (vt == VOLVERTEX) {
23876  setpointtype(ptloop, FREEVOLVERTEX);
23877  st_volref_count++;
23878  } else if (vt == FACETVERTEX) {
23879  setpointtype(ptloop, FREEFACETVERTEX);
23880  st_facref_count++;
23881  } else if (vt == RIDGEVERTEX) {
23882  idx = pointmark(ptloop) - in->firstnumber;
23883  if ((idx2seglist[idx + 1] - idx2seglist[idx]) == 2) {
23884  i = idx2seglist[idx];
23885  parentseg = segperverlist[i];
23886  nextseg = segperverlist[i + 1];
23887  sesymself(nextseg);
23888  p[0] = sorg(nextseg);
23889  p[1] = sdest(parentseg);
23890  // Check if three points p[0], ptloop, p[2] are (nearly) collinear.
23891  len = distance(p[0], p[1]);
23892  l1 = distance(p[0], ptloop);
23893  l2 = distance(ptloop, p[1]);
23894  if (((l1 + l2 - len) / len) < b->epsilon) {
23895  // They are (nearly) collinear.
23896  setpointtype(ptloop, FREESEGVERTEX);
23897  // Connect nextseg and parentseg together at ptloop.
23898  senextself(nextseg);
23899  senext2self(parentseg);
23900  sbond(nextseg, parentseg);
23901  st_segref_count++;
23902  }
23903  }
23904  }
23905  ptloop = pointtraverse();
23906  }
23907 
23908  // Are there area constraints?
23909  if (b->quality && (in->facetconstraintlist != (REAL *) NULL)) {
23910  // Set maximum area constraints on facets.
23911  for (i = 0; i < in->numberoffacetconstraints; i++) {
23912  fmarker = (int) in->facetconstraintlist[i * 2];
23913  area = in->facetconstraintlist[i * 2 + 1];
23914  subfaces->traversalinit();
23915  subloop.sh = shellfacetraverse(subfaces);
23916  while (subloop.sh != NULL) {
23917  if (shellmark(subloop) == fmarker) {
23918  setareabound(subloop, area);
23919  }
23920  subloop.sh = shellfacetraverse(subfaces);
23921  }
23922  }
23923  }
23924 
23925  // Are there length constraints?
23926  if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) {
23927  // Set maximum length constraints on segments.
23928  int e1, e2;
23929  for (i = 0; i < in->numberofsegmentconstraints; i++) {
23930  e1 = (int) in->segmentconstraintlist[i * 3];
23931  e2 = (int) in->segmentconstraintlist[i * 3 + 1];
23932  len = in->segmentconstraintlist[i * 3 + 2];
23933  // Search for edge [e1, e2].
23934  idx = e1 - in->firstnumber;
23935  for (j = idx2seglist[idx]; j < idx2seglist[idx + 1]; j++) {
23936  parentseg = segperverlist[j];
23937  if (pointmark(sdest(parentseg)) == e2) {
23938  setareabound(parentseg, len);
23939  break;
23940  }
23941  }
23942  }
23943  }
23944 
23945  delete [] idx2seglist;
23946  delete [] segperverlist;
23947  }
23948 
23949 
23950  // Set global flags.
23951  checksubsegflag = 1;
23952  checksubfaceflag = 1;
23953 
23954  delete [] idx2verlist;
23955  delete [] ver2tetarray;
23956 }
23957 
23959 // //
23960 // scoutpoint() Search a point in mesh. //
23961 // //
23962 // This function searches the point in a mesh whose domain may be not convex.//
23963 // In case of a convex domain, the locate() function is sufficient. //
23964 // //
23965 // If 'randflag' is used, randomly select a start searching tet. Otherwise, //
23966 // start searching directly from 'searchtet'. //
23967 // //
23969 
23970 int tetgenmesh::scoutpoint(point searchpt, triface *searchtet, int randflag)
23971 {
23972  point pa, pb, pc, pd;
23973  enum locateresult loc = OUTSIDE;
23974  REAL vol, ori1, ori2 = 0, ori3 = 0, ori4 = 0;
23975  int t1ver;
23976 
23977 
23978  // Randomly select a good starting tet.
23979  if (randflag) {
23980  randomsample(searchpt, searchtet);
23981  } else {
23982  if (searchtet->tet == NULL) {
23983  *searchtet = recenttet;
23984  }
23985  }
23986  loc = locate(searchpt, searchtet);
23987 
23988  if (loc == OUTSIDE) {
23989  if (b->convex) { // -c option
23990  // The point lies outside of the convex hull.
23991  return (int) loc;
23992  }
23993  // Test if it lies nearly on the hull face.
23994  // Reuse vol, ori1.
23995  pa = org(*searchtet);
23996  pb = dest(*searchtet);
23997  pc = apex(*searchtet);
23998  vol = triarea(pa, pb, pc);
23999  ori1 = orient3dfast(pa, pb, pc, searchpt);
24000  if (fabs(ori1 / vol) < b->epsilon) {
24001  loc = ONFACE; // On face (or on edge, or on vertex).
24002  fsymself(*searchtet);
24003  }
24004  }
24005 
24006  if (loc != OUTSIDE) {
24007  // Round the result of location.
24008  pa = org(*searchtet);
24009  pb = dest(*searchtet);
24010  pc = apex(*searchtet);
24011  pd = oppo(*searchtet);
24012  vol = orient3dfast(pa, pb, pc, pd);
24013  ori1 = orient3dfast(pa, pb, pc, searchpt);
24014  ori2 = orient3dfast(pb, pa, pd, searchpt);
24015  ori3 = orient3dfast(pc, pb, pd, searchpt);
24016  ori4 = orient3dfast(pa, pc, pd, searchpt);
24017  if (fabs(ori1 / vol) < b->epsilon) ori1 = 0;
24018  if (fabs(ori2 / vol) < b->epsilon) ori2 = 0;
24019  if (fabs(ori3 / vol) < b->epsilon) ori3 = 0;
24020  if (fabs(ori4 / vol) < b->epsilon) ori4 = 0;
24021  } else { // if (loc == OUTSIDE) {
24022  // Do a brute force search for the point (with rounding).
24023  tetrahedrons->traversalinit();
24024  searchtet->tet = tetrahedrontraverse();
24025  while (searchtet->tet != NULL) {
24026  pa = org(*searchtet);
24027  pb = dest(*searchtet);
24028  pc = apex(*searchtet);
24029  pd = oppo(*searchtet);
24030 
24031  vol = orient3dfast(pa, pb, pc, pd);
24032  if (vol < 0) {
24033  ori1 = orient3dfast(pa, pb, pc, searchpt);
24034  if (fabs(ori1 / vol) < b->epsilon) ori1 = 0; // Rounding.
24035  if (ori1 <= 0) {
24036  ori2 = orient3dfast(pb, pa, pd, searchpt);
24037  if (fabs(ori2 / vol) < b->epsilon) ori2 = 0;
24038  if (ori2 <= 0) {
24039  ori3 = orient3dfast(pc, pb, pd, searchpt);
24040  if (fabs(ori3 / vol) < b->epsilon) ori3 = 0;
24041  if (ori3 <= 0) {
24042  ori4 = orient3dfast(pa, pc, pd, searchpt);
24043  if (fabs(ori4 / vol) < b->epsilon) ori4 = 0;
24044  if (ori4 <= 0) {
24045  // Found the tet. Return its location.
24046  break;
24047  } // ori4
24048  } // ori3
24049  } // ori2
24050  } // ori1
24051  }
24052 
24053  searchtet->tet = tetrahedrontraverse();
24054  } // while (searchtet->tet != NULL)
24055  nonregularcount++; // Re-use this counter.
24056  }
24057 
24058  if (searchtet->tet != NULL) {
24059  // Return the point location.
24060  if (ori1 == 0) { // on face [a,b,c]
24061  if (ori2 == 0) { // on edge [a,b].
24062  if (ori3 == 0) { // on vertex [b].
24063  enextself(*searchtet); // [b,c,a,d]
24064  loc = ONVERTEX;
24065  } else {
24066  if (ori4 == 0) { // on vertex [a]
24067  loc = ONVERTEX; // [a,b,c,d]
24068  } else {
24069  loc = ONEDGE; // [a,b,c,d]
24070  }
24071  }
24072  } else { // ori2 != 0
24073  if (ori3 == 0) { // on edge [b,c]
24074  if (ori4 == 0) { // on vertex [c]
24075  eprevself(*searchtet); // [c,a,b,d]
24076  loc = ONVERTEX;
24077  } else {
24078  enextself(*searchtet); // [b,c,a,d]
24079  loc = ONEDGE;
24080  }
24081  } else { // ori3 != 0
24082  if (ori4 == 0) { // on edge [c,a]
24083  eprevself(*searchtet); // [c,a,b,d]
24084  loc = ONEDGE;
24085  } else {
24086  loc = ONFACE;
24087  }
24088  }
24089  }
24090  } else { // ori1 != 0
24091  if (ori2 == 0) { // on face [b,a,d]
24092  esymself(*searchtet); // [b,a,d,c]
24093  if (ori3 == 0) { // on edge [b,d]
24094  eprevself(*searchtet); // [d,b,a,c]
24095  if (ori4 == 0) { // on vertex [d]
24096  loc = ONVERTEX;
24097  } else {
24098  loc = ONEDGE;
24099  }
24100  } else { // ori3 != 0
24101  if (ori4 == 0) { // on edge [a,d]
24102  enextself(*searchtet); // [a,d,b,c]
24103  loc = ONEDGE;
24104  } else {
24105  loc = ONFACE;
24106  }
24107  }
24108  } else { // ori2 != 0
24109  if (ori3 == 0) { // on face [c,b,d]
24110  enextself(*searchtet);
24111  esymself(*searchtet);
24112  if (ori4 == 0) { // on edge [c,d]
24113  eprevself(*searchtet);
24114  loc = ONEDGE;
24115  } else {
24116  loc = ONFACE;
24117  }
24118  } else {
24119  if (ori4 == 0) { // on face [a,c,d]
24120  eprevself(*searchtet);
24121  esymself(*searchtet);
24122  loc = ONFACE;
24123  } else { // inside tet [a,b,c,d]
24124  loc = INTETRAHEDRON;
24125  } // ori4
24126  } // ori3
24127  } // ori2
24128  } // ori1
24129  } else {
24130  loc = OUTSIDE;
24131  }
24132 
24133  return (int) loc;
24134 }
24135 
24137 // //
24138 // getpointmeshsize() Interpolate the mesh size at given point. //
24139 // //
24140 // 'iloc' indicates the location of the point w.r.t. 'searchtet'. The size //
24141 // is obtained by linear interpolation on the vertices of the tet. //
24142 // //
24144 
24145 REAL tetgenmesh::getpointmeshsize(point searchpt, triface *searchtet, int iloc)
24146 {
24147  point *pts, pa, pb, pc;
24148  REAL volume, vol[4], wei[4];
24149  REAL size;
24150  int i;
24151 
24152  size = 0;
24153 
24154  if (iloc == (int) INTETRAHEDRON) {
24155  pts = (point *) &(searchtet->tet[4]);
24156  // Only do interpolation if all vertices have non-zero sizes.
24157  if ((pts[0][pointmtrindex] > 0) && (pts[1][pointmtrindex] > 0) &&
24158  (pts[2][pointmtrindex] > 0) && (pts[3][pointmtrindex] > 0)) {
24159  // P1 interpolation.
24160  volume = orient3dfast(pts[0], pts[1], pts[2], pts[3]);
24161  vol[0] = orient3dfast(searchpt, pts[1], pts[2], pts[3]);
24162  vol[1] = orient3dfast(pts[0], searchpt, pts[2], pts[3]);
24163  vol[2] = orient3dfast(pts[0], pts[1], searchpt, pts[3]);
24164  vol[3] = orient3dfast(pts[0], pts[1], pts[2], searchpt);
24165  for (i = 0; i < 4; i++) {
24166  wei[i] = fabs(vol[i] / volume);
24167  size += (wei[i] * pts[i][pointmtrindex]);
24168  }
24169  }
24170  } else if (iloc == (int) ONFACE) {
24171  pa = org(*searchtet);
24172  pb = dest(*searchtet);
24173  pc = apex(*searchtet);
24174  if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) &&
24175  (pc[pointmtrindex] > 0)) {
24176  volume = triarea(pa, pb, pc);
24177  vol[0] = triarea(searchpt, pb, pc);
24178  vol[1] = triarea(pa, searchpt, pc);
24179  vol[2] = triarea(pa, pb, searchpt);
24180  size = (vol[0] / volume) * pa[pointmtrindex]
24181  + (vol[1] / volume) * pb[pointmtrindex]
24182  + (vol[2] / volume) * pc[pointmtrindex];
24183  }
24184  } else if (iloc == (int) ONEDGE) {
24185  pa = org(*searchtet);
24186  pb = dest(*searchtet);
24187  if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0)) {
24188  volume = distance(pa, pb);
24189  vol[0] = distance(searchpt, pb);
24190  vol[1] = distance(pa, searchpt);
24191  size = (vol[0] / volume) * pa[pointmtrindex]
24192  + (vol[1] / volume) * pb[pointmtrindex];
24193  }
24194  } else if (iloc == (int) ONVERTEX) {
24195  pa = org(*searchtet);
24196  if (pa[pointmtrindex] > 0) {
24197  size = pa[pointmtrindex];
24198  }
24199  }
24200 
24201  return size;
24202 }
24203 
24205 // //
24206 // interpolatemeshsize() Interpolate the mesh size from a background mesh //
24207 // (source) to the current mesh (destination). //
24208 // //
24210 
24211 void tetgenmesh::interpolatemeshsize()
24212 {
24213  triface searchtet;
24214  point ploop;
24215  REAL minval = 0.0, maxval = 0.0;
24216  int iloc;
24217  int count;
24218 
24219  if (!b->quiet) {
24220  printf("Interpolating mesh size ...\n");
24221  }
24222 
24223  long bak_nonregularcount = nonregularcount;
24224  nonregularcount = 0l; // Count the number of (slow) global searches.
24225  long baksmaples = bgm->samples;
24226  bgm->samples = 3l;
24227  count = 0; // Count the number of interpolated points.
24228 
24229  // Interpolate sizes for all points in the current mesh.
24230  points->traversalinit();
24231  ploop = pointtraverse();
24232  while (ploop != NULL) {
24233  // Search a tet in bgm which containing this point.
24234  searchtet.tet = NULL;
24235  iloc = bgm->scoutpoint(ploop, &searchtet, 1); // randflag = 1
24236  if (iloc != (int) OUTSIDE) {
24237  // Interpolate the mesh size.
24238  ploop[pointmtrindex] = bgm->getpointmeshsize(ploop, &searchtet, iloc);
24239  setpoint2bgmtet(ploop, bgm->encode(searchtet));
24240  if (count == 0) {
24241  // This is the first interpolated point.
24242  minval = maxval = ploop[pointmtrindex];
24243  } else {
24244  if (ploop[pointmtrindex] < minval) {
24245  minval = ploop[pointmtrindex];
24246  }
24247  if (ploop[pointmtrindex] > maxval) {
24248  maxval = ploop[pointmtrindex];
24249  }
24250  }
24251  count++;
24252  } else {
24253  if (!b->quiet) {
24254  printf("Warnning: Failed to locate point %d in source mesh.\n",
24255  pointmark(ploop));
24256  }
24257  }
24258  ploop = pointtraverse();
24259  }
24260 
24261  if (b->verbose) {
24262  printf(" Interoplated %d points.\n", count);
24263  if (nonregularcount > 0l) {
24264  printf(" Performed %ld brute-force searches.\n", nonregularcount);
24265  }
24266  printf(" Size rangle [%.17g, %.17g].\n", minval, maxval);
24267  }
24268 
24269  bgm->samples = baksmaples;
24270  nonregularcount = bak_nonregularcount;
24271 }
24272 
24274 // //
24275 // insertconstrainedpoints() Insert a list of points into the mesh. //
24276 // //
24277 // Assumption: The bounding box of the insert point set should be no larger //
24278 // than the bounding box of the mesh. (Required by point sorting). //
24279 // //
24281 
24282 void tetgenmesh::insertconstrainedpoints(point *insertarray, int arylen,
24283  int rejflag)
24284 {
24285  triface searchtet, spintet;
24286  face splitsh;
24287  face splitseg;
24288  insertvertexflags ivf;
24289  flipconstraints fc;
24290  int randflag = 0;
24291  int t1ver;
24292  int i;
24293 
24294  if (b->verbose) {
24295  printf(" Inserting %d constrained points\n", arylen);
24296  }
24297 
24298  if (b->no_sort) { // -b/1 option.
24299  if (b->verbose) {
24300  printf(" Using the input order.\n");
24301  }
24302  } else {
24303  if (b->verbose) {
24304  printf(" Permuting vertices.\n");
24305  }
24306  point swappoint;
24307  int randindex;
24308  srand(arylen);
24309  for (i = 0; i < arylen; i++) {
24310  randindex = rand() % (i + 1);
24311  swappoint = insertarray[i];
24312  insertarray[i] = insertarray[randindex];
24313  insertarray[randindex] = swappoint;
24314  }
24315  if (b->brio_hilbert) { // -b1 option
24316  if (b->verbose) {
24317  printf(" Sorting vertices.\n");
24318  }
24319  hilbert_init(in->mesh_dim);
24320  int ngroup = 0;
24321  brio_multiscale_sort(insertarray, arylen, b->brio_threshold,
24322  b->brio_ratio, &ngroup);
24323  } else { // -b0 option.
24324  randflag = 1;
24325  } // if (!b->brio_hilbert)
24326  } // if (!b->no_sort)
24327 
24328  long bak_nonregularcount = nonregularcount;
24329  nonregularcount = 0l;
24330  long baksmaples = samples;
24331  samples = 3l; // Use at least 3 samples. Updated in randomsample().
24332 
24333  long bak_seg_count = st_segref_count;
24334  long bak_fac_count = st_facref_count;
24335  long bak_vol_count = st_volref_count;
24336 
24337  // Initialize the insertion parameters.
24338  if (b->incrflip) { // -l option
24339  // Use incremental flip algorithm.
24340  ivf.bowywat = 0;
24341  ivf.lawson = 1;
24342  ivf.validflag = 0; // No need to validate the cavity.
24343  fc.enqflag = 2;
24344  } else {
24345  // Use Bowyer-Watson algorithm.
24346  ivf.bowywat = 1;
24347  ivf.lawson = 0;
24348  ivf.validflag = 1; // Validate the B-W cavity.
24349  }
24350  ivf.rejflag = rejflag;
24351  ivf.chkencflag = 0;
24352  ivf.sloc = (int) INSTAR;
24353  ivf.sbowywat = 3;
24354  ivf.splitbdflag = 1;
24355  ivf.respectbdflag = 1;
24356  ivf.assignmeshsize = b->metric;
24357 
24358  encseglist = new arraypool(sizeof(face), 8);
24359  encshlist = new arraypool(sizeof(badface), 8);
24360 
24361  // Insert the points.
24362  for (i = 0; i < arylen; i++) {
24363  // Find the location of the inserted point.
24364  // Do not use 'recenttet', since the mesh may be non-convex.
24365  searchtet.tet = NULL;
24366  ivf.iloc = scoutpoint(insertarray[i], &searchtet, randflag);
24367 
24368  // Decide the right type for this point.
24369  setpointtype(insertarray[i], FREEVOLVERTEX); // Default.
24370  splitsh.sh = NULL;
24371  splitseg.sh = NULL;
24372  if (ivf.iloc == (int) ONEDGE) {
24373  if (issubseg(searchtet)) {
24374  tsspivot1(searchtet, splitseg);
24375  setpointtype(insertarray[i], FREESEGVERTEX);
24376  //ivf.rejflag = 0;
24377  } else {
24378  // Check if it is a subface edge.
24379  spintet = searchtet;
24380  while (1) {
24381  if (issubface(spintet)) {
24382  tspivot(spintet, splitsh);
24383  setpointtype(insertarray[i], FREEFACETVERTEX);
24384  //ivf.rejflag |= 1;
24385  break;
24386  }
24387  fnextself(spintet);
24388  if (spintet.tet == searchtet.tet) break;
24389  }
24390  }
24391  } else if (ivf.iloc == (int) ONFACE) {
24392  if (issubface(searchtet)) {
24393  tspivot(searchtet, splitsh);
24394  setpointtype(insertarray[i], FREEFACETVERTEX);
24395  //ivf.rejflag |= 1;
24396  }
24397  }
24398 
24399  // Now insert the point.
24400  if (insertpoint(insertarray[i], &searchtet, &splitsh, &splitseg, &ivf)) {
24401  if (flipstack != NULL) {
24402  // There are queued faces. Use flips to recover Delaunayness.
24403  lawsonflip3d(&fc);
24404  // There may be unflippable edges. Ignore them.
24405  unflipqueue->restart();
24406  }
24407  // Update the Steiner counters.
24408  if (pointtype(insertarray[i]) == FREESEGVERTEX) {
24409  st_segref_count++;
24410  } else if (pointtype(insertarray[i]) == FREEFACETVERTEX) {
24411  st_facref_count++;
24412  } else {
24413  st_volref_count++;
24414  }
24415  } else {
24416  // Point is not inserted.
24417  //pointdealloc(insertarray[i]);
24418  setpointtype(insertarray[i], UNUSEDVERTEX);
24419  unuverts++;
24420  encseglist->restart();
24421  encshlist->restart();
24422  }
24423  } // i
24424 
24425  delete encseglist;
24426  delete encshlist;
24427 
24428  if (b->verbose) {
24429  printf(" Inserted %ld (%ld, %ld, %ld) vertices.\n",
24430  st_segref_count + st_facref_count + st_volref_count -
24431  (bak_seg_count + bak_fac_count + bak_vol_count),
24432  st_segref_count - bak_seg_count, st_facref_count - bak_fac_count,
24433  st_volref_count - bak_vol_count);
24434  if (nonregularcount > 0l) {
24435  printf(" Performed %ld brute-force searches.\n", nonregularcount);
24436  }
24437  }
24438 
24439  nonregularcount = bak_nonregularcount;
24440  samples = baksmaples;
24441 }
24442 
24443 void tetgenmesh::insertconstrainedpoints(tetgenio *addio)
24444 {
24445  point *insertarray, newpt;
24446  REAL x, y, z, w;
24447  int index, attribindex, mtrindex;
24448  int arylen, i, j;
24449 
24450  if (!b->quiet) {
24451  printf("Inserting constrained points ...\n");
24452  }
24453 
24454  insertarray = new point[addio->numberofpoints];
24455  arylen = 0;
24456  index = 0;
24457  attribindex = 0;
24458  mtrindex = 0;
24459 
24460  for (i = 0; i < addio->numberofpoints; i++) {
24461  x = addio->pointlist[index++];
24462  y = addio->pointlist[index++];
24463  z = addio->pointlist[index++];
24464  // Test if this point lies inside the bounding box.
24465  if ((x < xmin) || (x > xmax) || (y < ymin) || (y > ymax) ||
24466  (z < zmin) || (z > zmax)) {
24467  if (b->verbose) {
24468  printf("Warning: Point #%d lies outside the bounding box. Ignored\n",
24469  i + in->firstnumber);
24470  }
24471  continue;
24472  }
24473  makepoint(&newpt, UNUSEDVERTEX);
24474  newpt[0] = x;
24475  newpt[1] = y;
24476  newpt[2] = z;
24477  // Read the point attributes. (Including point weights.)
24478  for (j = 0; j < addio->numberofpointattributes; j++) {
24479  newpt[3 + j] = addio->pointattributelist[attribindex++];
24480  }
24481  // Read the point metric tensor.
24482  for (j = 0; j < addio->numberofpointmtrs; j++) {
24483  newpt[pointmtrindex + j] = addio->pointmtrlist[mtrindex++];
24484  }
24485  if (b->weighted) { // -w option
24486  if (addio->numberofpointattributes > 0) {
24487  // The first point attribute is its weight.
24488  w = newpt[3];
24489  } else {
24490  // No given weight available. Default choose the maximum
24491  // absolute value among its coordinates.
24492  w = fabs(x);
24493  if (w < fabs(y)) w = fabs(y);
24494  if (w < fabs(z)) w = fabs(z);
24495  }
24496  if (b->weighted_param == 0) {
24497  newpt[3] = x * x + y * y + z * z - w; // Weighted DT.
24498  } else { // -w1 option
24499  newpt[3] = w; // Regular tetrahedralization.
24500  }
24501  }
24502  insertarray[arylen] = newpt;
24503  arylen++;
24504  } // i
24505 
24506  // Insert the points.
24507  int rejflag = 0; // Do not check encroachment.
24508  if (b->metric) { // -m option.
24509  rejflag |= 4; // Reject it if it lies in some protecting balls.
24510  }
24511 
24512  insertconstrainedpoints(insertarray, arylen, rejflag);
24513 
24514  delete [] insertarray;
24515 }
24516 
24518 // //
24519 // meshcoarsening() Deleting (selected) vertices. //
24520 // //
24522 
24523 void tetgenmesh::collectremovepoints(arraypool *remptlist)
24524 {
24525  point ptloop, *parypt;
24526  verttype vt;
24527 
24528  // If a mesh sizing function is given. Collect vertices whose mesh size
24529  // is greater than its smallest edge length.
24530  if (b->metric) { // -m option
24531  REAL len, smlen;
24532  int i;
24533  points->traversalinit();
24534  ptloop = pointtraverse();
24535  while (ptloop != NULL) {
24536  // Do not remove a boundary vertex
24537  vt = pointtype(ptloop);
24538  if ((vt == RIDGEVERTEX) || (vt == ACUTEVERTEX) || (vt == FACETVERTEX) ||
24539  (vt == FREEFACETVERTEX) || (vt == FREESEGVERTEX) || (vt == UNUSEDVERTEX)) {
24540  ptloop = pointtraverse();
24541  continue;
24542  }
24543  if (ptloop[pointmtrindex] > 0) {
24544  // Get the smallest edge length at this vertex.
24545  getvertexstar(1, ptloop, cavetetlist, cavetetvertlist, NULL);
24546  parypt = (point *) fastlookup(cavetetvertlist, 0);
24547  smlen = distance(ptloop, *parypt);
24548  for (i = 1; i < cavetetvertlist->objects; i++) {
24549  parypt = (point *) fastlookup(cavetetvertlist, i);
24550  len = distance(ptloop, *parypt);
24551  if (len < smlen) {
24552  smlen = len;
24553  }
24554  }
24555  cavetetvertlist->restart();
24556  cavetetlist->restart();
24557  if (smlen < ptloop[pointmtrindex]) {
24558  pinfect(ptloop);
24559  remptlist->newindex((void **) &parypt);
24560  *parypt = ptloop;
24561  }
24562  }
24563  ptloop = pointtraverse();
24564  }
24565  if (b->verbose > 1) {
24566  printf(" Coarsen %ld oversized points.\n", remptlist->objects);
24567  }
24568  }
24569 
24570  // If 'in->pointmarkerlist' exists, Collect vertices with markers '-1'.
24571  if (in->pointmarkerlist != NULL) {
24572  long bak_count = remptlist->objects;
24573  points->traversalinit();
24574  ptloop = pointtraverse();
24575  int index = 0;
24576  while (ptloop != NULL) {
24577  if (index < in->numberofpoints) {
24578  if (in->pointmarkerlist[index] == -1) {
24579  pinfect(ptloop);
24580  remptlist->newindex((void **) &parypt);
24581  *parypt = ptloop;
24582  }
24583  } else {
24584  // Remaining are not input points. Stop here.
24585  break;
24586  }
24587  index++;
24588  ptloop = pointtraverse();
24589  }
24590  if (b->verbose > 1) {
24591  printf(" Coarsen %ld marked points.\n", remptlist->objects - bak_count);
24592  }
24593  } // if (in->pointmarkerlist != NULL)
24594 
24595  if (b->coarsen_param > 0) { // -R1/#
24596  // Remove a coarsen_percent number of interior points.
24597  if (b->verbose > 1) {
24598  printf(" Coarsen %g percent of interior points.\n",
24599  b->coarsen_percent * 100.0);
24600  }
24601  arraypool *intptlist = new arraypool(sizeof(point *), 10);
24602  // Count the total number of interior points.
24603  points->traversalinit();
24604  ptloop = pointtraverse();
24605  while (ptloop != NULL) {
24606  vt = pointtype(ptloop);
24607  if ((vt == VOLVERTEX) || (vt == FREEVOLVERTEX) ||
24608  (vt == FREEFACETVERTEX) || (vt == FREESEGVERTEX)) {
24609  intptlist->newindex((void **) &parypt);
24610  *parypt = ptloop;
24611  }
24612  ptloop = pointtraverse();
24613  }
24614  if (intptlist->objects > 0l) {
24615  // Sort the list of points randomly.
24616  point *parypt_i, swappt;
24617  int randindex, i;
24618  srand(intptlist->objects);
24619  for (i = 0; i < intptlist->objects; i++) {
24620  randindex = rand() % (i + 1); // randomnation(i + 1);
24621  parypt_i = (point *) fastlookup(intptlist, i);
24622  parypt = (point *) fastlookup(intptlist, randindex);
24623  // Swap this two points.
24624  swappt = *parypt_i;
24625  *parypt_i = *parypt;
24626  *parypt = swappt;
24627  }
24628  int remcount = (int) ((REAL) intptlist->objects * b->coarsen_percent);
24629  // Return the first remcount points.
24630  for (i = 0; i < remcount; i++) {
24631  parypt_i = (point *) fastlookup(intptlist, i);
24632  if (!pinfected(*parypt_i)) {
24633  pinfected(*parypt_i);
24634  remptlist->newindex((void **) &parypt);
24635  *parypt = *parypt_i;
24636  }
24637  }
24638  }
24639  delete intptlist;
24640  }
24641 
24642  // Unmark all collected vertices.
24643  for (int i = 0; i < remptlist->objects; i++) {
24644  parypt = (point *) fastlookup(remptlist, i);
24645  puninfect(*parypt);
24646  }
24647 }
24648 
24649 void tetgenmesh::meshcoarsening()
24650 {
24651  arraypool *remptlist;
24652 
24653  if (!b->quiet) {
24654  printf("Mesh coarsening ...\n");
24655  }
24656 
24657  // Collect the set of points to be removed
24658  remptlist = new arraypool(sizeof(point *), 10);
24659  collectremovepoints(remptlist);
24660 
24661  if (remptlist->objects == 0l) {
24662  delete remptlist;
24663  return;
24664  }
24665 
24666  if (b->verbose) {
24667  if (remptlist->objects > 0l) {
24668  printf(" Removing %ld points...\n", remptlist->objects);
24669  }
24670  }
24671 
24672  point *parypt, *plastpt;
24673  long ms = remptlist->objects;
24674  int nit = 0;
24675  int bak_fliplinklevel = b->fliplinklevel;
24676  b->fliplinklevel = -1;
24677  autofliplinklevel = 1; // Init value.
24678  int i;
24679 
24680  while (1) {
24681 
24682  if (b->verbose > 1) {
24683  printf(" Removing points [%s level = %2d] #: %ld.\n",
24684  (b->fliplinklevel > 0) ? "fixed" : "auto",
24685  (b->fliplinklevel > 0) ? b->fliplinklevel : autofliplinklevel,
24686  remptlist->objects);
24687  }
24688 
24689  // Remove the list of points.
24690  for (i = 0; i < remptlist->objects; i++) {
24691  parypt = (point *) fastlookup(remptlist, i);
24692  if (removevertexbyflips(*parypt)) {
24693  // Move the last entry to the current place.
24694  plastpt = (point *) fastlookup(remptlist, remptlist->objects - 1);
24695  *parypt = *plastpt;
24696  remptlist->objects--;
24697  i--;
24698  }
24699  }
24700 
24701  if (remptlist->objects > 0l) {
24702  if (b->fliplinklevel >= 0) {
24703  break; // We have tried all levels.
24704  }
24705  if (remptlist->objects == ms) {
24706  nit++;
24707  if (nit >= 3) {
24708  // Do the last round with unbounded flip link level.
24709  b->fliplinklevel = 100000;
24710  }
24711  } else {
24712  ms = remptlist->objects;
24713  if (nit > 0) {
24714  nit--;
24715  }
24716  }
24717  autofliplinklevel+=b->fliplinklevelinc;
24718  } else {
24719  // All points are removed.
24720  break;
24721  }
24722  } // while (1)
24723 
24724  if (remptlist->objects > 0l) {
24725  if (b->verbose) {
24726  printf(" %ld points are not removed !\n", remptlist->objects);
24727  }
24728  }
24729 
24730  b->fliplinklevel = bak_fliplinklevel;
24731  delete remptlist;
24732 }
24733 
24737 
24741 
24743 // //
24744 // makefacetverticesmap() Create a map from facet to its vertices. //
24745 // //
24746 // All facets will be indexed (starting from 0). The map is saved in two //
24747 // global arrays: 'idx2facetlist' and 'facetverticeslist'. //
24748 // //
24750 
24751 void tetgenmesh::makefacetverticesmap()
24752 {
24753  arraypool *facetvertexlist, *vertlist, **paryvertlist;
24754  face subloop, neighsh, *parysh, *parysh1;
24755  point pa, *ppt, *parypt;
24756  verttype vt;
24757  int facetindex, totalvertices;
24758  int i, j, k;
24759 
24760  if (b->verbose) {
24761  printf(" Creating the facet vertices map.\n");
24762  }
24763 
24764  facetvertexlist = new arraypool(sizeof(arraypool *), 10);
24765  facetindex = totalvertices = 0;
24766 
24767  subfaces->traversalinit();
24768  subloop.sh = shellfacetraverse(subfaces);
24769  while (subloop.sh != NULL) {
24770  if (!sinfected(subloop)) {
24771  // A new facet. Create its vertices list.
24772  vertlist = new arraypool(sizeof(point *), 8);
24773  ppt = (point *) &(subloop.sh[3]);
24774  for (k = 0; k < 3; k++) {
24775  vt = pointtype(ppt[k]);
24776  if ((vt != FREESEGVERTEX) && (vt != FREEFACETVERTEX)) {
24777  pinfect(ppt[k]);
24778  vertlist->newindex((void **) &parypt);
24779  *parypt = ppt[k];
24780  }
24781  }
24782  sinfect(subloop);
24783  caveshlist->newindex((void **) &parysh);
24784  *parysh = subloop;
24785  for (i = 0; i < caveshlist->objects; i++) {
24786  parysh = (face *) fastlookup(caveshlist, i);
24787  setfacetindex(*parysh, facetindex);
24788  for (j = 0; j < 3; j++) {
24789  if (!isshsubseg(*parysh)) {
24790  spivot(*parysh, neighsh);
24791  if (!sinfected(neighsh)) {
24792  pa = sapex(neighsh);
24793  if (!pinfected(pa)) {
24794  vt = pointtype(pa);
24795  if ((vt != FREESEGVERTEX) && (vt != FREEFACETVERTEX)) {
24796  pinfect(pa);
24797  vertlist->newindex((void **) &parypt);
24798  *parypt = pa;
24799  }
24800  }
24801  sinfect(neighsh);
24802  caveshlist->newindex((void **) &parysh1);
24803  *parysh1 = neighsh;
24804  }
24805  }
24806  senextself(*parysh);
24807  }
24808  } // i
24809  totalvertices += (int) vertlist->objects;
24810  // Uninfect facet vertices.
24811  for (k = 0; k < vertlist->objects; k++) {
24812  parypt = (point *) fastlookup(vertlist, k);
24813  puninfect(*parypt);
24814  }
24815  caveshlist->restart();
24816  // Save this vertex list.
24817  facetvertexlist->newindex((void **) &paryvertlist);
24818  *paryvertlist = vertlist;
24819  facetindex++;
24820  }
24821  subloop.sh = shellfacetraverse(subfaces);
24822  }
24823 
24824  // All subfaces are infected. Uninfect them.
24825  subfaces->traversalinit();
24826  subloop.sh = shellfacetraverse(subfaces);
24827  while (subloop.sh != NULL) {
24828  suninfect(subloop);
24829  subloop.sh = shellfacetraverse(subfaces);
24830  }
24831 
24832  if (b->verbose) {
24833  printf(" Found %ld facets.\n", facetvertexlist->objects);
24834  }
24835 
24836  idx2facetlist = new int[facetindex + 1];
24837  facetverticeslist = new point[totalvertices];
24838 
24839  totalworkmemory += ((facetindex + 1) * sizeof(int) +
24840  totalvertices * sizeof(point *));
24841 
24842  idx2facetlist[0] = 0;
24843  for (i = 0, k = 0; i < facetindex; i++) {
24844  paryvertlist = (arraypool **) fastlookup(facetvertexlist, i);
24845  vertlist = *paryvertlist;
24846  idx2facetlist[i + 1] = (idx2facetlist[i] + (int) vertlist->objects);
24847  for (j = 0; j < vertlist->objects; j++) {
24848  parypt = (point *) fastlookup(vertlist, j);
24849  facetverticeslist[k] = *parypt;
24850  k++;
24851  }
24852  }
24853 
24854  // Free the lists.
24855  for (i = 0; i < facetvertexlist->objects; i++) {
24856  paryvertlist = (arraypool **) fastlookup(facetvertexlist, i);
24857  vertlist = *paryvertlist;
24858  delete vertlist;
24859  }
24860  delete facetvertexlist;
24861 }
24862 
24864 // //
24865 // Check whether two segments, or a segment and a facet, or two facets are //
24866 // adjacent to each other. //
24867 // //
24869 
24870 int tetgenmesh::segsegadjacent(face *seg1, face *seg2)
24871 {
24872  int segidx1 = getfacetindex(*seg1);
24873  int segidx2 = getfacetindex(*seg2);
24874 
24875  if (segidx1 == segidx2) return 0;
24876 
24877  point pa1 = segmentendpointslist[segidx1 * 2];
24878  point pb1 = segmentendpointslist[segidx1 * 2 + 1];
24879  point pa2 = segmentendpointslist[segidx2 * 2];
24880  point pb2 = segmentendpointslist[segidx2 * 2 + 1];
24881 
24882  if ((pa1 == pa2) || (pa1 == pb2) || (pb1 == pa2) || (pb1 == pb2)) {
24883  return 1;
24884  }
24885  return 0;
24886 }
24887 
24888 int tetgenmesh::segfacetadjacent(face *subseg, face *subsh)
24889 {
24890  int segidx = getfacetindex(*subseg);
24891  point pa = segmentendpointslist[segidx * 2];
24892  point pb = segmentendpointslist[segidx * 2 + 1];
24893 
24894  pinfect(pa);
24895  pinfect(pb);
24896 
24897  int fidx = getfacetindex(*subsh);
24898  int count = 0, i;
24899 
24900  for (i = idx2facetlist[fidx]; i < idx2facetlist[fidx+1]; i++) {
24901  if (pinfected(facetverticeslist[i])) count++;
24902  }
24903 
24904  puninfect(pa);
24905  puninfect(pb);
24906 
24907  return count == 1;
24908 }
24909 
24910 int tetgenmesh::facetfacetadjacent(face *subsh1, face *subsh2)
24911 {
24912  int count = 0, i;
24913 
24914  int fidx1 = getfacetindex(*subsh1);
24915  int fidx2 = getfacetindex(*subsh2);
24916 
24917  if (fidx1 == fidx2) return 0;
24918 
24919  for (i = idx2facetlist[fidx1]; i < idx2facetlist[fidx1+1]; i++) {
24920  pinfect(facetverticeslist[i]);
24921  }
24922 
24923  for (i = idx2facetlist[fidx2]; i < idx2facetlist[fidx2+1]; i++) {
24924  if (pinfected(facetverticeslist[i])) count++;
24925  }
24926 
24927  // Uninfect the vertices.
24928  for (i = idx2facetlist[fidx1]; i < idx2facetlist[fidx1+1]; i++) {
24929  puninfect(facetverticeslist[i]);
24930  }
24931 
24932  return count > 0;
24933 }
24934 
24936 // //
24937 // save_segmentpoint_insradius(), save_facetpoint_insradius() //
24938 // //
24939 // Determine and save the relaxed insertion radius of a Steiner point on a //
24940 // segment or a facet. By default, it is the closet distance to the parent //
24941 // point of this Steiner point. But may be larger than it. //
24942 // //
24944 
24945 void tetgenmesh::save_segmentpoint_insradius(point segpt,point parentpt,REAL r)
24946 {
24947  REAL rv = r, rp;
24948  if (pointtype(parentpt) == FREESEGVERTEX) {
24949  face parentseg1, parentseg2;
24950  sdecode(point2sh(segpt), parentseg1);
24951  sdecode(point2sh(parentpt), parentseg2);
24952  if (segsegadjacent(&parentseg1, &parentseg2)) {
24953  rp = getpointinsradius(parentpt);
24954  if (rv < rp) {
24955  // The relaxed insertion radius of 'newpt'.
24956  rv = rp;
24957  }
24958  }
24959  } else if (pointtype(parentpt) == FREEFACETVERTEX) {
24960  face parentseg, parentsh;
24961  sdecode(point2sh(segpt), parentseg);
24962  sdecode(point2sh(parentpt), parentsh);
24963  if (segfacetadjacent(&parentseg, &parentsh)) {
24964  rp = getpointinsradius(parentpt);
24965  if ((sqrt(2.0) * rv) < rp) { // if (rv < rp) {
24966  // The relaxed insertion radius of 'newpt'.
24967  rv = rp / sqrt(2.0); // rv = rp;
24968  }
24969  }
24970  }
24971  setpointinsradius(segpt, rv);
24972 }
24973 
24974 void tetgenmesh::save_facetpoint_insradius(point facpt,point parentpt,REAL r)
24975 {
24976  REAL rv = r, rp;
24977  if (pointtype(parentpt) == FREESEGVERTEX) {
24978  face parentseg, parentsh;
24979  sdecode(point2sh(parentpt), parentseg);
24980  sdecode(point2sh(facpt), parentsh);
24981  if (segfacetadjacent(&parentseg, &parentsh)) {
24982  rp = getpointinsradius(parentpt);
24983  if (rv < (sqrt(2.0) * rp)) {
24984  rv = sqrt(2.0) * rp; // The relaxed insertion radius of 'newpt'.
24985  }
24986  }
24987  } else if (pointtype(parentpt) == FREEFACETVERTEX) {
24988  face parentsh1, parentsh2;
24989  sdecode(point2sh(parentpt), parentsh1);
24990  sdecode(point2sh(facpt), parentsh2);
24991  if (facetfacetadjacent(&parentsh1, &parentsh2)) {
24992  rp = getpointinsradius(parentpt);
24993  if (rv < rp) {
24994  rv = rp; // The relaxed insertion radius of 'newpt'.
24995  }
24996  }
24997  }
24998  setpointinsradius(facpt, rv);
24999 }
25000 
25002 // //
25003 // enqueuesubface() Queue a subface or a subsegment for encroachment chk. //
25004 // //
25006 
25007 void tetgenmesh::enqueuesubface(memorypool *pool, face *chkface)
25008 {
25009  if (!smarktest2ed(*chkface)) {
25010  smarktest2(*chkface); // Only queue it once.
25011  face *queface = (face *) pool->alloc();
25012  *queface = *chkface;
25013  }
25014 }
25015 
25017 // //
25018 // enqueuetetrahedron() Queue a tetrahedron for quality check. //
25019 // //
25021 
25022 void tetgenmesh::enqueuetetrahedron(triface *chktet)
25023 {
25024  if (!marktest2ed(*chktet)) {
25025  marktest2(*chktet); // Only queue it once.
25026  triface *quetet = (triface *) badtetrahedrons->alloc();
25027  *quetet = *chktet;
25028  }
25029 }
25030 
25032 // //
25033 // checkseg4encroach() Check if an edge is encroached upon by a point. //
25034 // //
25036 
25037 int tetgenmesh::checkseg4encroach(point pa, point pb, point checkpt)
25038 {
25039  // Check if the point lies inside the diametrical sphere of this seg.
25040  REAL v1[3], v2[3];
25041 
25042  v1[0] = pa[0] - checkpt[0];
25043  v1[1] = pa[1] - checkpt[1];
25044  v1[2] = pa[2] - checkpt[2];
25045  v2[0] = pb[0] - checkpt[0];
25046  v2[1] = pb[1] - checkpt[1];
25047  v2[2] = pb[2] - checkpt[2];
25048 
25049  if (dot(v1, v2) < 0) {
25050  // Inside.
25051  if (b->metric) { // -m option.
25052  if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0)) {
25053  // The projection of 'checkpt' lies inside the segment [a,b].
25054  REAL prjpt[3], u, v, t;
25055  projpt2edge(checkpt, pa, pb, prjpt);
25056  // Interoplate the mesh size at the location 'prjpt'.
25057  u = distance(pa, pb);
25058  v = distance(pa, prjpt);
25059  t = v / u;
25060  // 'u' is the mesh size at 'prjpt'
25061  u = pa[pointmtrindex] + t * (pb[pointmtrindex] - pa[pointmtrindex]);
25062  v = distance(checkpt, prjpt);
25063  if (v < u) {
25064  return 1; // Encroached prot-ball!
25065  }
25066  } else {
25067  return 1; // NO protecting ball. Encroached.
25068  }
25069  } else {
25070  return 1; // Inside! Encroached.
25071  }
25072  }
25073 
25074  return 0;
25075 }
25076 
25078 // //
25079 // checkseg4split() Check if we need to split a segment. //
25080 // //
25081 // A segment needs to be split if it is in the following case: //
25082 // (1) It is encroached by an existing vertex. //
25083 // (2) It has bad quality (too long). //
25084 // (3) Its length is larger than the mesh sizes at its endpoints. //
25085 // //
25086 // Return 1 if it needs to be split, otherwise, return 0. 'pencpt' returns //
25087 // an encroaching point if there exists. 'qflag' returns '1' if the segment //
25088 // has a length larger than the desired edge length. //
25089 // //
25091 
25092 int tetgenmesh::checkseg4split(face *chkseg, point& encpt, int& qflag)
25093 {
25094  REAL ccent[3], len, r;
25095  int i;
25096 
25097  point forg = sorg(*chkseg);
25098  point fdest = sdest(*chkseg);
25099 
25100  // Initialize the return values.
25101  encpt = NULL;
25102  qflag = 0;
25103 
25104  len = distance(forg, fdest);
25105  r = 0.5 * len;
25106  for (i = 0; i < 3; i++) {
25107  ccent[i] = 0.5 * (forg[i] + fdest[i]);
25108  }
25109 
25110  // First check its quality.
25111  if (checkconstraints && (areabound(*chkseg) > 0.0)) {
25112  if (len > areabound(*chkseg)) {
25113  qflag = 1;
25114  return 1;
25115  }
25116  }
25117 
25118  if (b->fixedvolume) {
25119  if ((len * len * len) > b->maxvolume) {
25120  qflag = 1;
25121  return 1;
25122  }
25123  }
25124 
25125  if (b->metric) { // -m option. Check mesh size.
25126  // Check if the ccent lies outside one of the prot.balls at vertices.
25127  if (((forg[pointmtrindex] > 0) && (r > forg[pointmtrindex])) ||
25128  ((fdest[pointmtrindex]) > 0 && (r > fdest[pointmtrindex]))) {
25129  qflag = 1; // Enforce mesh size.
25130  return 1;
25131  }
25132  }
25133 
25134 
25135  // Second check if it is encroached.
25136  // Comment: There may exist more than one encroaching points of this segment.
25137  // The 'encpt' returns the one which is closet to it.
25138  triface searchtet, spintet;
25139  point eapex;
25140  REAL d, diff, smdist = 0;
25141  int t1ver;
25142 
25143  sstpivot1(*chkseg, searchtet);
25144  spintet = searchtet;
25145  while (1) {
25146  eapex = apex(spintet);
25147  if (eapex != dummypoint) {
25148  d = distance(ccent, eapex);
25149  diff = d - r;
25150  if (fabs(diff) / r < b->epsilon) diff = 0.0; // Rounding.
25151  if (diff < 0) {
25152  // This segment is encroached by eapex.
25153  if (useinsertradius) {
25154  if (encpt == NULL) {
25155  encpt = eapex;
25156  smdist = d;
25157  } else {
25158  // Choose the closet encroaching point.
25159  if (d < smdist) {
25160  encpt = eapex;
25161  smdist = d;
25162  }
25163  }
25164  } else {
25165  encpt = eapex;
25166  break;
25167  }
25168  }
25169  }
25170  fnextself(spintet);
25171  if (spintet.tet == searchtet.tet) break;
25172  } // while (1)
25173 
25174  if (encpt != NULL) {
25175  return 1;
25176  }
25177 
25178  return 0; // No need to split it.
25179 }
25180 
25182 // //
25183 // splitsegment() Split a segment. //
25184 // //
25185 // The segment 'splitseg' is intended to be split. It will be split if it //
25186 // is in one of the following cases: //
25187 // (1) It is encroached by an existing vertex 'encpt != NULL'; or //
25188 // (2) It is in bad quality 'qflag == 1'; or //
25189 // (3) Its length is larger than the mesh sizes at its endpoints. //
25190 // //
25192 #pragma GCC diagnostic push
25193 #pragma GCC diagnostic ignored "-Wunused-parameter"
25194 int tetgenmesh::splitsegment(face *splitseg, point encpt, REAL rrp,
25195  point encpt1, point encpt2, int qflag,
25196  int chkencflag)
25197 {
25198 
25199  if (!qflag && smarktest3ed(*splitseg)) {
25200  // Do not try to re-split a marked segment.
25201  return 0;
25202  }
25203 
25204  if (b->nobisect) { // With -Y option.
25205  // Only split this segment if it is allowed to be split.
25206  if (checkconstraints) {
25207  // Check if it has a non-zero length bound.
25208  if (areabound(*splitseg) == 0) {
25209  // It is not allowed. However, if all of facets containing this seg
25210  // is allowed to be split, we still split it.
25211  face parentsh, spinsh;
25212  //splitseg.shver = 0;
25213  spivot(*splitseg, parentsh);
25214  if (parentsh.sh == NULL) {
25215  return 0; // A dangling segment. Do not split it.
25216  }
25217  spinsh = parentsh;
25218  while (1) {
25219  if (areabound(spinsh) == 0) break;
25220  spivotself(spinsh);
25221  if (spinsh.sh == parentsh.sh) break;
25222  if (spinsh.sh == NULL) break; // It belongs to only one facet.
25223  }
25224  if ((!spinsh.sh) || (areabound(spinsh) == 0)) {
25225  // All facets at this seg are not allowed to be split.
25226  return 0; // Do not split it.
25227  }
25228  }
25229  } else {
25230  return 0; // Do not split this segment.
25231  }
25232  } // if (b->nobisect)
25233 
25234  triface searchtet;
25235  face searchsh;
25236  point newpt;
25237  insertvertexflags ivf;
25238 
25239  makepoint(&newpt, FREESEGVERTEX);
25240  getsteinerptonsegment(splitseg, encpt, newpt);
25241 
25242  if (!qflag && !b->cdtrefine) {
25243  // Do not insert the point if it encroaches upon an adjacent segment.
25244  face parentsh;
25245  spivot(*splitseg, parentsh);
25246  if (parentsh.sh != NULL) {
25247  face spinsh, neighsh;
25248  face neighseg;
25249  spinsh = parentsh;
25250  while (1) {
25251  for (int i = 0; i < 2; i++) {
25252  if (i == 0) {
25253  senext(spinsh, neighsh);
25254  } else {
25255  senext2(spinsh, neighsh);
25256  }
25257  if (isshsubseg(neighsh)) {
25258  sspivot(neighsh, neighseg);
25259  if (checkseg4encroach(sorg(neighseg), sdest(neighseg), newpt)) {
25260  pointdealloc(newpt);
25261  return 0; // Do not split this segment.
25262  }
25263  }
25264  } // i
25265  spivotself(spinsh);
25266  if (spinsh.sh == NULL) break;
25267  if (spinsh.sh == parentsh.sh) break;
25268  } // while (1)
25269  }
25270  }
25271 
25272  // Split the segment by the Bowyer-Watson algorithm.
25273  sstpivot1(*splitseg, searchtet);
25274  ivf.iloc = (int) ONEDGE;
25275  ivf.bowywat = 3; // Use Bowyer-Watson, preserve subsegments and subfaces;
25276  ivf.validflag = 1; // Validate the B-W cavity.
25277  ivf.lawson = 2; // Do flips to recover Delaunayness.
25278  ivf.rejflag = 0; // Do not check encroachment of new segments/facets.
25279  if (b->metric) {
25280  ivf.rejflag |= 4; // Do check encroachment of protecting balls.
25281  }
25282  ivf.chkencflag = chkencflag;
25283  ivf.sloc = (int) INSTAR; // ivf.iloc;
25284  ivf.sbowywat = 3; // ivf.bowywat; // Surface mesh options.
25285  ivf.splitbdflag = 1;
25286  ivf.respectbdflag = 1;
25287  ivf.assignmeshsize = b->metric;
25288  ivf.smlenflag = useinsertradius; // Return the closet mesh vertex.
25289 
25290 
25291  if (insertpoint(newpt, &searchtet, &searchsh, splitseg, &ivf)) {
25292  st_segref_count++;
25293  if (steinerleft > 0) steinerleft--;
25294  if (useinsertradius) {
25295  save_segmentpoint_insradius(newpt, ivf.parentpt, ivf.smlen);
25296  }
25297  if (flipstack != NULL) {
25298  flipconstraints fc;
25299  fc.chkencflag = chkencflag;
25300  fc.enqflag = 2;
25301  lawsonflip3d(&fc);
25302  unflipqueue->restart();
25303  }
25304  return 1;
25305  } else {
25306  // Point is not inserted.
25307  if (ivf.iloc == (int) NEARVERTEX) {
25308  terminatetetgen(this, 2);
25309  }
25310  pointdealloc(newpt);
25311  // Mark this segment to avoid splitting in the future.
25312  smarktest3(*splitseg);
25313  return 0;
25314  }
25315 }
25316 #pragma GCC diagnostic pop
25317 // //
25319 // repairencsegs() Repair encroached (sub) segments. //
25320 // //
25322 
25323 void tetgenmesh::repairencsegs(int chkencflag)
25324 {
25325  face *bface;
25326  point encpt = NULL;
25327  int qflag = 0;
25328 
25329  // Loop until the pool 'badsubsegs' is empty. Note that steinerleft == -1
25330  // if an unlimited number of Steiner points is allowed.
25331  while ((badsubsegs->items > 0) && (steinerleft != 0)) {
25332  badsubsegs->traversalinit();
25333  bface = (face *) badsubsegs->traverse();
25334  while ((bface != NULL) && (steinerleft != 0)) {
25335  // Skip a deleleted element.
25336  if (bface->shver >= 0) {
25337  // A queued segment may have been deleted (split).
25338  if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
25339  // A queued segment may have been processed.
25340  if (smarktest2ed(*bface)) {
25341  sunmarktest2(*bface);
25342  if (checkseg4split(bface, encpt, qflag)) {
25343  splitsegment(bface, encpt, 0, NULL, NULL, qflag, chkencflag);
25344  }
25345  }
25346  }
25347  // Remove this entry from list.
25348  bface->shver = -1; // Signal it as a deleted element.
25349  badsubsegs->dealloc((void *) bface);
25350  }
25351  bface = (face *) badsubsegs->traverse();
25352  }
25353  }
25354 
25355  if (badsubsegs->items > 0) {
25356  if (b->verbose) {
25357  printf("The desired number of Steiner points is reached.\n");
25358  }
25359  badsubsegs->traversalinit();
25360  bface = (face *) badsubsegs->traverse();
25361  while (bface != NULL) {
25362  // Skip a deleleted element.
25363  if (bface->shver >= 0) {
25364  if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
25365  if (smarktest2ed(*bface)) {
25366  sunmarktest2(*bface);
25367  }
25368  }
25369  }
25370  bface = (face *) badsubsegs->traverse();
25371  }
25372  badsubsegs->restart();
25373  }
25374 }
25375 
25377 // //
25378 // checkfac4encroach() Check if a subface is encroached by a point. //
25379 // //
25381 
25382 int tetgenmesh::checkfac4encroach(point pa, point pb, point pc, point checkpt,
25383  REAL* cent, REAL* r)
25384 {
25385  REAL rd, len;
25386  int encroached = 0;
25387 
25388  circumsphere(pa, pb, pc, NULL, cent, &rd);
25389  if (rd == 0) {
25390  terminatetetgen(this, 2);
25391  }
25392 
25393  if (b->use_equatorial_lens) {
25394  REAL normal[3], fcenter[3];
25395  REAL xta, yta, zta;
25396  REAL multiplier;
25397 
25398  fcenter[0] = cent[0] - pc[0];
25399  fcenter[1] = cent[1] - pc[1];
25400  fcenter[2] = cent[2] - pc[2];
25401 
25402  // Get the normal of the oriented face [a->b->c], without normalized.
25403  facenormal(pa, pb, pc, normal, 1, NULL);
25404  multiplier = 0.985 * sqrt((fcenter[0]*fcenter[0] + fcenter[1]*fcenter[1] +
25405  fcenter[2]*fcenter[2]) /
25406  (3.0 * (normal[0] * normal[0] + normal[1] * normal[1] +
25407  normal[2] * normal[2])));
25408  xta = checkpt[0] - pc[0];
25409  yta = checkpt[1] - pc[1];
25410  zta = checkpt[2] - pc[2];
25411  // Make sure that the normal is pointing to "checkpt".
25412  if ((xta * normal[0] + yta * normal[1] + zta * normal[2]) < 0) {
25413  // Reverse the normal direction.
25414  normal[0] = -normal[0];
25415  normal[1] = -normal[1];
25416  normal[2] = -normal[2];
25417  }
25418 
25419  if (xta * xta + yta * yta + zta * zta <=
25420  2.0 * (xta * (fcenter[0] - multiplier * normal[0]) +
25421  yta * (fcenter[1] - multiplier * normal[1]) +
25422  zta * (fcenter[2] - multiplier * normal[2]))) {
25423  encroached = 1;
25424  }
25425  } else {
25426  len = distance(cent, checkpt);
25427  if ((fabs(len - rd) / rd) < b->epsilon) len = rd; // Rounding.
25428  if (len < rd) {
25429  encroached = 1;
25430  }
25431  }
25432 
25433  if (encroached) {
25434  // The point lies inside the circumsphere of this face.
25435  if (b->metric) { // -m option.
25436  if ((pa[pointmtrindex] > 0) && (pb[pointmtrindex] > 0) &&
25437  (pc[pointmtrindex] > 0)) {
25438  // Get the projection of 'checkpt' in the plane of pa, pb, and pc.
25439  REAL prjpt[3], n[3];
25440  REAL a, a1, a2, a3;
25441  projpt2face(checkpt, pa, pb, pc, prjpt);
25442  // Get the face area of [a,b,c].
25443  facenormal(pa, pb, pc, n, 1, NULL);
25444  a = sqrt(dot(n,n));
25445  // Get the face areas of [a,b,p], [b,c,p], and [c,a,p].
25446  facenormal(pa, pb, prjpt, n, 1, NULL);
25447  a1 = sqrt(dot(n,n));
25448  facenormal(pb, pc, prjpt, n, 1, NULL);
25449  a2 = sqrt(dot(n,n));
25450  facenormal(pc, pa, prjpt, n, 1, NULL);
25451  a3 = sqrt(dot(n,n));
25452  if ((fabs(a1 + a2 + a3 - a) / a) < b->epsilon) {
25453  // This face contains the projection.
25454  // Get the mesh size at the location of the projection point.
25455  rd = a1 / a * pc[pointmtrindex]
25456  + a2 / a * pa[pointmtrindex]
25457  + a3 / a * pb[pointmtrindex];
25458  len = distance(prjpt, checkpt);
25459  if (len < rd) {
25460  return 1; // Encroached.
25461  }
25462  }
25463  } else {
25464  return 1; // No protecting ball. Encroached.
25465  }
25466  } else {
25467  *r = rd;
25468  return 1; // Encroached.
25469  }
25470  }
25471 
25472  return 0;
25473 }
25474 
25476 // //
25477 // checkfac4split() Check if a subface needs to be split. //
25478 // //
25479 // A subface needs to be split if it is in the following case: //
25480 // (1) It is encroached by an existing vertex. //
25481 // (2) It has bad quality (has a small angle, -q). //
25482 // (3) It's area is larger than a prescribed value (.var). //
25483 // //
25484 // Return 1 if it needs to be split, otherwise, return 0. //
25485 // 'chkfac' represents its longest edge. //
25486 // //
25488 
25489 int tetgenmesh::checkfac4split(face *chkfac, point& encpt, int& qflag,
25490  REAL *cent)
25491 {
25492  point pa, pb, pc;
25493  REAL area, rd, len;
25494  REAL A[4][4], rhs[4], D;
25495  int indx[4];
25496  int i;
25497 
25498  encpt = NULL;
25499  qflag = 0;
25500 
25501  pa = sorg(*chkfac);
25502  pb = sdest(*chkfac);
25503  pc = sapex(*chkfac);
25504 
25505  // Compute the coefficient matrix A (3x3).
25506  A[0][0] = pb[0] - pa[0];
25507  A[0][1] = pb[1] - pa[1];
25508  A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
25509  A[1][0] = pc[0] - pa[0];
25510  A[1][1] = pc[1] - pa[1];
25511  A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
25512  cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
25513 
25514  area = 0.5 * sqrt(dot(A[2], A[2])); // The area of [a,b,c].
25515 
25516  // Compute the right hand side vector b (3x1).
25517  rhs[0] = 0.5 * dot(A[0], A[0]); // edge [a,b]
25518  rhs[1] = 0.5 * dot(A[1], A[1]); // edge [a,c]
25519  rhs[2] = 0.0;
25520 
25521  // Solve the 3 by 3 equations use LU decomposition with partial
25522  // pivoting and backward and forward substitute.
25523  if (!lu_decmp(A, 3, indx, &D, 0)) {
25524  // A degenerate triangle.
25525  terminatetetgen(this, 2);
25526  }
25527 
25528  lu_solve(A, 3, indx, rhs, 0);
25529  cent[0] = pa[0] + rhs[0];
25530  cent[1] = pa[1] + rhs[1];
25531  cent[2] = pa[2] + rhs[2];
25532  rd = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
25533 
25534  if (checkconstraints && (areabound(*chkfac) > 0.0)) {
25535  // Check if the subface has too big area.
25536  if (area > areabound(*chkfac)) {
25537  qflag = 1;
25538  return 1;
25539  }
25540  }
25541 
25542  if (b->fixedvolume) {
25543  if ((area * sqrt(area)) > b->maxvolume) {
25544  qflag = 1;
25545  return 1;
25546  }
25547  }
25548 
25549  if (b->varvolume) {
25550  triface adjtet;
25551  REAL volbnd;
25552  int t1ver;
25553 
25554  stpivot(*chkfac, adjtet);
25555  if (!ishulltet(adjtet)) {
25556  volbnd = volumebound(adjtet.tet);
25557  if ((volbnd > 0) && (area * sqrt(area)) > volbnd) {
25558  qflag = 1;
25559  return 1;
25560  }
25561  }
25562  fsymself(adjtet);
25563  if (!ishulltet(adjtet)) {
25564  volbnd = volumebound(adjtet.tet);
25565  if ((volbnd > 0) && (area * sqrt(area)) > volbnd) {
25566  qflag = 1;
25567  return 1;
25568  }
25569  }
25570  }
25571 
25572  if (b->metric) { // -m option. Check mesh size.
25573  // Check if the ccent lies outside one of the prot.balls at vertices.
25574  if (((pa[pointmtrindex] > 0) && (rd > pa[pointmtrindex])) ||
25575  ((pb[pointmtrindex] > 0) && (rd > pb[pointmtrindex])) ||
25576  ((pc[pointmtrindex] > 0) && (rd > pc[pointmtrindex]))) {
25577  qflag = 1; // Enforce mesh size.
25578  return 1;
25579  }
25580  }
25581 
25582  triface searchtet;
25583  REAL smlen = 0;
25584 
25585  // Check if this subface is locally encroached.
25586  for (i = 0; i < 2; i++) {
25587  stpivot(*chkfac, searchtet);
25588  if (!ishulltet(searchtet)) {
25589  int encroached = 0;
25590 
25591  len = distance(oppo(searchtet), cent);
25592  if ((fabs(len - rd) / rd) < b->epsilon) len = rd;// Rounding.
25593 
25594  if (b->use_equatorial_lens) {
25595  point tettapex = oppo(searchtet);
25596  REAL normal[3], fcenter[3];
25597  REAL xta, yta, zta;
25598  REAL multiplier;
25599  // Get the normal of the oriented face [a->b->c], without normalized.
25600  point fa = org(searchtet);
25601  point fb = dest(searchtet);
25602  point fc = apex(searchtet);
25603 
25604  fcenter[0] = cent[0] - fc[0];
25605  fcenter[1] = cent[1] - fc[1];
25606  fcenter[2] = cent[2] - fc[2];
25607 
25608  facenormal(fa, fb, fc, normal, 1, NULL);
25609  multiplier = 0.985 * sqrt((fcenter[0]*fcenter[0] + fcenter[1]*fcenter[1] +
25610  fcenter[2]*fcenter[2]) /
25611  (3.0 * (normal[0] * normal[0] + normal[1] * normal[1] +
25612  normal[2] * normal[2])));
25613  xta = tettapex[0] - fc[0];
25614  yta = tettapex[1] - fc[1];
25615  zta = tettapex[2] - fc[2];
25616  if (xta * xta + yta * yta + zta * zta <=
25617  2.0 * (xta * (fcenter[0] - multiplier * normal[0]) +
25618  yta * (fcenter[1] - multiplier * normal[1]) +
25619  zta * (fcenter[2] - multiplier * normal[2]))) {
25620  encroached = 1;
25621  }
25622  } else {
25623  if (len < rd) {
25624  encroached = 1;
25625  }
25626  }
25627 
25628  if (encroached) {
25629  if (smlen == 0) {
25630  smlen = len;
25631  encpt = oppo(searchtet);
25632  } else {
25633  if (len < smlen) {
25634  smlen = len;
25635  encpt = oppo(searchtet);
25636  }
25637  }
25638  //return 1;
25639  }
25640  }
25641  sesymself(*chkfac);
25642  }
25643 
25644  return encpt != NULL; //return 0;
25645 }
25646 
25648 // //
25649 // splitsubface() Split a subface. //
25650 // //
25651 // The subface may be encroached, or in bad-quality. It is split at its cir- //
25652 // cumcenter ('ccent'). Do not split it if 'ccent' encroaches upon any seg- //
25653 // ment. Instead, one of the encroached segments is split. It is possible //
25654 // that none of the encroached segments can be split. //
25655 // //
25656 // The return value indicates whether a new point is inserted (> 0) or not //
25657 // (= 0). Furthermore, it is inserted on an encroached segment (= 1) or //
25658 // in-side the facet (= 2). //
25659 // //
25660 // 'encpt' is a vertex encroaching upon this subface, i.e., it causes the //
25661 // split of this subface. If 'encpt' is NULL, then the cause of the split //
25662 // this subface is a rejected tet circumcenter 'p', and 'encpt1' is the //
25663 // parent of 'p'. //
25664 // //
25666 
25667 int tetgenmesh::splitsubface(face *splitfac, point encpt, point encpt1,
25668  int qflag, REAL *ccent, int chkencflag)
25669 {
25670 
25671  if (!qflag && smarktest3ed(*splitfac)) {
25672  // Do not try to re-split a marked subface.
25673  return 0;
25674  }
25675 
25676  if (b->nobisect) { // With -Y option.
25677  if (checkconstraints) {
25678  // Only split if it is allowed to be split.
25679  // Check if this facet has a non-zero constraint.
25680  if (areabound(*splitfac) == 0) {
25681  return 0; // Do not split it.
25682  }
25683  } else {
25684  return 0;
25685  }
25686  } // if (b->nobisect)
25687 
25688  if (useinsertradius) {
25689  if (encpt != NULL) {
25690  REAL rp; // Insertion radius of newpt.
25691  REAL rv = distance(encpt, ccent);
25692  if (pointtype(encpt) == FREESEGVERTEX) {
25693  face parentseg;
25694  sdecode(point2sh(encpt), parentseg);
25695  if (segfacetadjacent(&parentseg, splitfac)) {
25696  rp = getpointinsradius(encpt);
25697  if (rv < (sqrt(2.0) * rp)) {
25698  // This insertion may cause no termination.
25699  return 0; // Reject the insertion of newpt.
25700  }
25701  }
25702  } else if (pointtype(encpt) == FREEFACETVERTEX) {
25703  face parentsh;
25704  sdecode(point2sh(encpt), parentsh);
25705  if (facetfacetadjacent(&parentsh, splitfac)) {
25706  rp = getpointinsradius(encpt);
25707  if (rv < rp) {
25708  return 0; // Reject the insertion of newpt.
25709  }
25710  }
25711  }
25712  }
25713  } // if (useinsertradius)
25714 
25715  face searchsh;
25716  insertvertexflags ivf;
25717  point newpt;
25718  int i;
25719 
25720  // Initialize the inserting point.
25721  makepoint(&newpt, FREEFACETVERTEX);
25722  // Split the subface at its circumcenter.
25723  for (i = 0; i < 3; i++) newpt[i] = ccent[i];
25724 
25725  // Search a subface which contains 'newpt'.
25726  searchsh = *splitfac;
25727  // Calculate an above point. It lies above the plane containing
25728  // the subface [a,b,c], and save it in dummypoint. Moreover,
25729  // the vector cent->dummypoint is the normal of the plane.
25730  calculateabovepoint4(newpt, sorg(*splitfac), sdest(*splitfac),
25731  sapex(*splitfac));
25732  // Parameters: 'aflag' = 1, - above point exists.
25733  // 'cflag' = 0, - non-convex, check co-planarity of the result.
25734  // 'rflag' = 0, - no need to round the locating result.
25735  ivf.iloc = (int) slocate(newpt, &searchsh, 1, 0, 0);
25736 
25737  if (!((ivf.iloc == (int) ONFACE) || (ivf.iloc == (int) ONEDGE))) {
25738  // Point location failed.
25739  pointdealloc(newpt);
25740  // Mark this subface to avoid splitting in the future.
25741  smarktest3(*splitfac);
25742  return 0;
25743  }
25744 
25745 
25746  triface searchtet;
25747 
25748  // Insert the point.
25749  stpivot(searchsh, searchtet);
25750  ivf.bowywat = 3; // Use Bowyer-Watson. Preserve subsegments and subfaces;
25751  ivf.lawson = 2;
25752  ivf.rejflag = 1; // Do check the encroachment of segments.
25753  if (b->metric) {
25754  ivf.rejflag |= 4; // Do check encroachment of protecting balls.
25755  }
25756  ivf.chkencflag = chkencflag;
25757  ivf.sloc = (int) INSTAR; // ivf.iloc;
25758  ivf.sbowywat = 3; // ivf.bowywat;
25759  ivf.splitbdflag = 1;
25760  ivf.validflag = 1;
25761  ivf.respectbdflag = 1;
25762  ivf.assignmeshsize = b->metric;
25763  ivf.refineflag = 2;
25764  ivf.refinesh = *splitfac;
25765  ivf.smlenflag = useinsertradius; // Update the insertion radius.
25766 
25767 
25768  if (insertpoint(newpt, &searchtet, &searchsh, NULL, &ivf)) {
25769  st_facref_count++;
25770  if (steinerleft > 0) steinerleft--;
25771  if (useinsertradius) {
25772  save_facetpoint_insradius(newpt, ivf.parentpt, ivf.smlen);
25773  } // if (useinsertradius)
25774  if (flipstack != NULL) {
25775  flipconstraints fc;
25776  fc.chkencflag = chkencflag;
25777  fc.enqflag = 2;
25778  lawsonflip3d(&fc);
25779  unflipqueue->restart();
25780  }
25781  return 1;
25782  } else {
25783  // Point was not inserted.
25784  pointdealloc(newpt);
25785  if (ivf.iloc == (int) ENCSEGMENT) {
25786  // Select an encroached segment and split it.
25787  face *paryseg;
25788  int splitflag = 0;
25789  for (i = 0; i < encseglist->objects; i++) {
25790  paryseg = (face *) fastlookup(encseglist, i);
25791  if (splitsegment(paryseg, NULL, 0.0, encpt, encpt1, qflag,
25792  chkencflag | 1)) {
25793  splitflag = 1; // A point is inserted on a segment.
25794  break;
25795  }
25796  } // i
25797  encseglist->restart();
25798  if (splitflag) {
25799  // Some segments may need to be repaired.
25800  if (badsubsegs->items > 0) {
25801  repairencsegs(chkencflag | 1);
25802  }
25803  return 1;
25804  }
25805  } else {
25806  if (ivf.iloc == (int) NEARVERTEX) {
25807  terminatetetgen(this, 2);
25808  }
25809  }
25810  // Mark this subface to avoid splitting in the future.
25811  smarktest3(*splitfac);
25812  return 0;
25813  }
25814 }
25815 
25817 // //
25818 // repairencfacs() Repair encroached subfaces. //
25819 // //
25821 
25822 void tetgenmesh::repairencfacs(int chkencflag)
25823 {
25824  face *bface;
25825  point encpt = NULL;
25826  int qflag = 0;
25827  REAL ccent[3];
25828 
25829  // Loop until the pool 'badsubfacs' is empty. Note that steinerleft == -1
25830  // if an unlimited number of Steiner points is allowed.
25831  while ((badsubfacs->items > 0) && (steinerleft != 0)) {
25832  badsubfacs->traversalinit();
25833  bface = (face *) badsubfacs->traverse();
25834  while ((bface != NULL) && (steinerleft != 0)) {
25835  // Skip a deleted element.
25836  if (bface->shver >= 0) {
25837  // A queued subface may have been deleted (split).
25838  if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
25839  // A queued subface may have been processed.
25840  if (smarktest2ed(*bface)) {
25841  sunmarktest2(*bface);
25842  if (checkfac4split(bface, encpt, qflag, ccent)) {
25843  splitsubface(bface, encpt, NULL, qflag, ccent, chkencflag);
25844  }
25845  }
25846  }
25847  bface->shver = -1; // Signal it as a deleted element.
25848  badsubfacs->dealloc((void *) bface); // Remove this entry from list.
25849  }
25850  bface = (face *) badsubfacs->traverse();
25851  }
25852  }
25853 
25854  if (badsubfacs->items > 0) {
25855  if (steinerleft == 0) {
25856  if (b->verbose) {
25857  printf("The desired number of Steiner points is reached.\n");
25858  }
25859  } else {
25860  terminatetetgen(this, 2);
25861  }
25862  badsubfacs->traversalinit();
25863  bface = (face *) badsubfacs->traverse();
25864  while (bface != NULL) {
25865  // Skip a deleted element.
25866  if (bface->shver >= 0) {
25867  if ((bface->sh != NULL) && (bface->sh[3] != NULL)) {
25868  if (smarktest2ed(*bface)) {
25869  sunmarktest2(*bface);
25870  }
25871  }
25872  }
25873  bface = (face *) badsubfacs->traverse();
25874  }
25875  badsubfacs->restart();
25876  }
25877 }
25878 
25880 // //
25881 // checktet4split() Check if the tet needs to be split. //
25882 // //
25884 
25885 int tetgenmesh::checktet4split(triface *chktet, int &qflag, REAL *ccent)
25886 {
25887  point pa, pb, pc, pd, *ppt;
25888  REAL vda[3], vdb[3], vdc[3];
25889  REAL vab[3], vbc[3], vca[3];
25890  REAL N[4][3], L[4], cosd[6], elen[6];
25891  REAL maxcosd, vol, volbnd, smlen = 0, rd;
25892  REAL A[4][4], rhs[4], D;
25893  int indx[4];
25894  int i, j;
25895 
25896  if (b->convex) { // -c
25897  // Skip this tet if it lies in the exterior.
25898  if (elemattribute(chktet->tet, numelemattrib - 1) == -1.0) {
25899  return 0;
25900  }
25901  }
25902 
25903  qflag = 0;
25904 
25905  pd = (point) chktet->tet[7];
25906  if (pd == dummypoint) {
25907  return 0; // Do not split a hull tet.
25908  }
25909 
25910  pa = (point) chktet->tet[4];
25911  pb = (point) chktet->tet[5];
25912  pc = (point) chktet->tet[6];
25913 
25914  // Get the edge vectors vda: d->a, vdb: d->b, vdc: d->c.
25915  // Set the matrix A = [vda, vdb, vdc]^T.
25916  for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i];
25917  for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i];
25918  for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i];
25919 
25920  // Get the other edge vectors.
25921  for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i];
25922  for (i = 0; i < 3; i++) vbc[i] = pc[i] - pb[i];
25923  for (i = 0; i < 3; i++) vca[i] = pa[i] - pc[i];
25924 
25925  if (!lu_decmp(A, 3, indx, &D, 0)) {
25926  // A degenerated tet (vol = 0).
25927  // This is possible due to the use of exact arithmetic. We temporarily
25928  // leave this tet. It should be fixed by mesh optimization.
25929  return 0;
25930  }
25931 
25932  // Check volume if '-a#' and '-a' options are used.
25933  if (b->varvolume || b->fixedvolume) {
25934  vol = fabs(A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0;
25935  if (b->fixedvolume) {
25936  if (vol > b->maxvolume) {
25937  qflag = 1;
25938  }
25939  }
25940  if (!qflag && b->varvolume) {
25941  volbnd = volumebound(chktet->tet);
25942  if ((volbnd > 0.0) && (vol > volbnd)) {
25943  qflag = 1;
25944  }
25945  }
25946  if (qflag == 1) {
25947  // Calculate the circumcenter of this tet.
25948  rhs[0] = 0.5 * dot(vda, vda);
25949  rhs[1] = 0.5 * dot(vdb, vdb);
25950  rhs[2] = 0.5 * dot(vdc, vdc);
25951  lu_solve(A, 3, indx, rhs, 0);
25952  for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25953  return 1;
25954  }
25955  }
25956 
25957  if (b->metric) { // -m option. Check mesh size.
25958  // Calculate the circumradius of this tet.
25959  rhs[0] = 0.5 * dot(vda, vda);
25960  rhs[1] = 0.5 * dot(vdb, vdb);
25961  rhs[2] = 0.5 * dot(vdc, vdc);
25962  lu_solve(A, 3, indx, rhs, 0);
25963  for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25964  rd = sqrt(dot(rhs, rhs));
25965  // Check if the ccent lies outside one of the prot.balls at vertices.
25966  ppt = (point *) &(chktet->tet[4]);
25967  for (i = 0; i < 4; i++) {
25968  if (ppt[i][pointmtrindex] > 0) {
25969  if (rd > ppt[i][pointmtrindex]) {
25970  qflag = 1; // Enforce mesh size.
25971  return 1;
25972  }
25973  }
25974  }
25975  }
25976 
25977  if (in->tetunsuitable != NULL) {
25978  // Execute the user-defined meshing sizing evaluation.
25979  if ((*(in->tetunsuitable))(pa, pb, pc, pd, NULL, 0)) {
25980  // Calculate the circumcenter of this tet.
25981  rhs[0] = 0.5 * dot(vda, vda);
25982  rhs[1] = 0.5 * dot(vdb, vdb);
25983  rhs[2] = 0.5 * dot(vdc, vdc);
25984  lu_solve(A, 3, indx, rhs, 0);
25985  for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
25986  return 1;
25987  }
25988  }
25989 
25990  if (useinsertradius) {
25991  // Do not split this tet if the shortest edge is shorter than the
25992  // insertion radius of one of its endpoints.
25993  triface checkedge;
25994  point e1, e2;
25995  REAL rrv, smrrv;
25996 
25997  // Get the shortest edge of this tet.
25998  checkedge.tet = chktet->tet;
25999  for (i = 0; i < 6; i++) {
26000  checkedge.ver = edge2ver[i];
26001  e1 = org(checkedge);
26002  e2 = dest(checkedge);
26003  elen[i] = distance(e1, e2);
26004  if (i == 0) {
26005  smlen = elen[i];
26006  j = 0;
26007  } else {
26008  if (elen[i] < smlen) {
26009  smlen = elen[i];
26010  j = i;
26011  }
26012  }
26013  }
26014  // Check if the edge is too short.
26015  checkedge.ver = edge2ver[j];
26016  // Get the smallest rrv of e1 and e2.
26017  // Note: if rrv of e1 and e2 is zero. Do not use it.
26018  e1 = org(checkedge);
26019  smrrv = getpointinsradius(e1);
26020  e2 = dest(checkedge);
26021  rrv = getpointinsradius(e2);
26022  if (rrv > 0) {
26023  if (smrrv > 0) {
26024  if (rrv < smrrv) {
26025  smrrv = rrv;
26026  }
26027  } else {
26028  smrrv = rrv;
26029  }
26030  }
26031  if (smrrv > 0) {
26032  // To avoid rounding error, round smrrv before doing comparison.
26033  if ((fabs(smrrv - smlen) / smlen) < b->epsilon) {
26034  smrrv = smlen;
26035  }
26036  if (smrrv > smlen) {
26037  return 0;
26038  }
26039  }
26040  } // if (useinsertradius)
26041 
26042  // Check the radius-edge ratio. Set by -q#.
26043  if (b->minratio > 0) {
26044  // Calculate the circumcenter and radius of this tet.
26045  rhs[0] = 0.5 * dot(vda, vda);
26046  rhs[1] = 0.5 * dot(vdb, vdb);
26047  rhs[2] = 0.5 * dot(vdc, vdc);
26048  lu_solve(A, 3, indx, rhs, 0);
26049  for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
26050  rd = sqrt(dot(rhs, rhs));
26051  if (!useinsertradius) {
26052  // Calculate the shortest edge length.
26053  elen[0] = dot(vda, vda);
26054  elen[1] = dot(vdb, vdb);
26055  elen[2] = dot(vdc, vdc);
26056  elen[3] = dot(vab, vab);
26057  elen[4] = dot(vbc, vbc);
26058  elen[5] = dot(vca, vca);
26059  smlen = elen[0]; //sidx = 0;
26060  for (i = 1; i < 6; i++) {
26061  if (smlen > elen[i]) {
26062  smlen = elen[i]; //sidx = i;
26063  }
26064  }
26065  smlen = sqrt(smlen);
26066  }
26067  D = rd / smlen;
26068  if (D > b->minratio) {
26069  // A bad radius-edge ratio.
26070  return 1;
26071  }
26072  }
26073 
26074  // Check the minimum dihedral angle. Set by -qq#.
26075  if (b->mindihedral > 0) {
26076  // Compute the 4 face normals (N[0], ..., N[3]).
26077  for (j = 0; j < 3; j++) {
26078  for (i = 0; i < 3; i++) N[j][i] = 0.0;
26079  N[j][j] = 1.0; // Positive means the inside direction
26080  lu_solve(A, 3, indx, N[j], 0);
26081  }
26082  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
26083  // Normalize the normals.
26084  for (i = 0; i < 4; i++) {
26085  L[i] = sqrt(dot(N[i], N[i]));
26086  if (L[i] == 0) {
26087  terminatetetgen(this, 2);
26088  }
26089  for (j = 0; j < 3; j++) N[i][j] /= L[i];
26090  }
26091  // Calculate the six dihedral angles.
26092  cosd[0] = -dot(N[0], N[1]); // Edge cd, bd, bc.
26093  cosd[1] = -dot(N[0], N[2]);
26094  cosd[2] = -dot(N[0], N[3]);
26095  cosd[3] = -dot(N[1], N[2]); // Edge ad, ac
26096  cosd[4] = -dot(N[1], N[3]);
26097  cosd[5] = -dot(N[2], N[3]); // Edge ab
26098  // Get the smallest dihedral angle.
26099  //maxcosd = mincosd = cosd[0];
26100  maxcosd = cosd[0];
26101  for (i = 1; i < 6; i++) {
26102  //if (cosd[i] > maxcosd) maxcosd = cosd[i];
26103  maxcosd = (cosd[i] > maxcosd ? cosd[i] : maxcosd);
26104  //mincosd = (cosd[i] < mincosd ? cosd[i] : maxcosd);
26105  }
26106  if (maxcosd > cosmindihed) {
26107  // Calculate the circumcenter of this tet.
26108  // A bad dihedral angle.
26109  //if ((b->quality & 1) == 0) {
26110  rhs[0] = 0.5 * dot(vda, vda);
26111  rhs[1] = 0.5 * dot(vdb, vdb);
26112  rhs[2] = 0.5 * dot(vdc, vdc);
26113  lu_solve(A, 3, indx, rhs, 0);
26114  for (i = 0; i < 3; i++) ccent[i] = pd[i] + rhs[i];
26115  //*rd = sqrt(dot(rhs, rhs));
26116  //}
26117  return 1;
26118  }
26119  }
26120 
26121  return 0;
26122 }
26123 
26125 // //
26126 // splittetrahedron() Split a tetrahedron. //
26127 // //
26129 
26130 int tetgenmesh::splittetrahedron(triface* splittet, int qflag, REAL *ccent,
26131  int chkencflag)
26132 {
26133  triface searchtet;
26134  face *paryseg;
26135  point newpt, *ppt;
26136  badface *bface;
26137  insertvertexflags ivf;
26138  int splitflag = 0;
26139  int i;
26140 
26141 
26142 
26143  REAL rv = 0.; // Insertion radius of 'newpt'.
26144 
26145  makepoint(&newpt, FREEVOLVERTEX);
26146  for (i = 0; i < 3; i++) newpt[i] = ccent[i];
26147 
26148 
26149  // Locate the new point. Starting from an interior point 'q' of the
26150  // splittet. We perform a walk from q to the 'newpt', stop walking
26151  // either we hit a subface or enter OUTSIDE.
26152  searchtet = *splittet;
26153  ivf.iloc = (int) OUTSIDE;
26154  ivf.iloc = locate(newpt, &searchtet, 1); // 'chkencflag' = 1.
26155 
26156  if ((ivf.iloc == (int) OUTSIDE) || (ivf.iloc == (int) ENCSUBFACE)) {
26157  // The circumcenter 'c' is not visible from 'q' (the interior of the tet).
26158 // iffalse
26159  if (b->verbose > 2) {
26160  printf(" New point %d is blocked by a polygon.\n", pointmark(newpt));
26161  }
26162 // \fi
26163  pointdealloc(newpt); // Do not insert this vertex.
26164  if (b->nobisect) return 0; // -Y option.
26165  // There must be a polygon that blocks the visibility.
26166  // Search a subpolygon that contains the proj(c).
26167  face searchsh;
26168  REAL prjpt[3];
26169  locateresult sloc = OUTSIDE;
26170  tspivot(searchtet, searchsh);
26171  ppt = (point *) &(searchsh.sh[3]);
26172  projpt2face(ccent, ppt[0], ppt[1], ppt[2], prjpt);
26173  // Locate proj(c) on polygon.
26174  sloc = slocate(prjpt, &searchsh, 0, 0, 1);
26175  if ((sloc == ONEDGE) || (sloc == ONFACE)) {
26176  // Found a subface/edge containing proj(c).
26177  // Check if 'c' encoraches upon this subface.
26178  REAL fcent[3], r = 0;
26179  ppt = (point *) &(searchsh.sh[3]);
26180  if (checkfac4encroach(ppt[0], ppt[1], ppt[2], ccent, fcent, &r)) {
26181  // Encroached. Split this subface.
26182  splitflag = splitsubface(&searchsh, NULL, org(*splittet), qflag,
26183  fcent, chkencflag | 2);
26184  if (splitflag) {
26185  // Some subfaces may need to be repaired.
26186  repairencfacs(chkencflag | 2);
26187  }
26188  }
26189  }
26190  else if ((sloc == OUTSIDE) || (sloc == ENCSEGMENT)) {
26191  // Hit a segment. We should split it.
26192  // To be done...
26193  // printf("hit segment, split it.\n"); // For debug only
26194  }
26195  if (splitflag) {
26196  // Queue the tet if it is still alive.
26197  if ((splittet->tet != NULL) && (splittet->tet[4] != NULL)) {
26198  enqueuetetrahedron(splittet);
26199  }
26200  }
26201  return splitflag;
26202  }
26203 
26204 
26205 
26206  // Use Bowyer-Watson algorithm. Preserve subsegments and subfaces;
26207  ivf.bowywat = 3;
26208  ivf.lawson = 2;
26209  ivf.rejflag = 3; // Do check for encroached segments and subfaces.
26210  if (b->metric) {
26211  ivf.rejflag |= 4; // Reject it if it lies in some protecting balls.
26212  }
26213  ivf.chkencflag = chkencflag;
26214  ivf.sloc = ivf.sbowywat = 0; // No use.
26215  ivf.splitbdflag = 0; // No use.
26216  ivf.validflag = 1;
26217  ivf.respectbdflag = 1;
26218  ivf.assignmeshsize = b->metric;
26219 
26220  ivf.refineflag = 1;
26221  ivf.refinetet = *splittet;
26222  if (useinsertradius) {
26223  // Need to save insertion radius for this new point.
26224  ivf.smlenflag = 1; // Return the shortest edge length after inserting
26225  // the new vertex. [2016-09-19]
26226  }
26227 
26228 
26229  if (insertpoint(newpt, &searchtet, NULL, NULL, &ivf)) {
26230  // Vertex is inserted.
26231  st_volref_count++;
26232  if (steinerleft > 0) steinerleft--;
26233  if (useinsertradius) {
26234  setpointinsradius(newpt, ivf.smlen);
26235  setpoint2ppt(newpt, ivf.parentpt);
26236  }
26237  if (flipstack != NULL) {
26238  flipconstraints fc;
26239  fc.chkencflag = chkencflag;
26240  fc.enqflag = 2;
26241  lawsonflip3d(&fc);
26242  unflipqueue->restart();
26243  }
26244  return 1;
26245  } else {
26246  // Point is not inserted.
26247  pointdealloc(newpt);
26248  // Check if there are encroached segments/subfaces.
26249  if (ivf.iloc == (int) ENCSEGMENT) {
26250  if (!b->nobisect || checkconstraints) {
26251  // Select an encroached segment and split it.
26252  for (i = 0; i < encseglist->objects; i++) {
26253  paryseg = (face *) fastlookup(encseglist, i);
26254  if (splitsegment(paryseg, NULL, rv, org(*splittet), NULL, qflag,
26255  chkencflag | 3)) {
26256  splitflag = 1; // A point is inserted on a segment.
26257  break;
26258  }
26259  }
26260  } // if (!b->nobisect)
26261  encseglist->restart();
26262  if (splitflag) {
26263  // Some segments may need to be repaired.
26264  if (badsubsegs->items > 0) {
26265  repairencsegs(chkencflag | 3);
26266  }
26267  // Some subfaces may need to be repaired.
26268  if (badsubfacs->items > 0) {
26269  repairencfacs(chkencflag | 2);
26270  }
26271  }
26272  } else if (ivf.iloc == (int) ENCSUBFACE) {
26273  if (!b->nobisect || checkconstraints) {
26274  // Select an encroached subface and split it.
26275  for (i = 0; i < encshlist->objects; i++) {
26276  bface = (badface *) fastlookup(encshlist, i);
26277  if (splitsubface(&(bface->ss), NULL, org(*splittet), qflag,
26278  bface->cent, chkencflag | 2)){
26279  splitflag = 1; // A point is inserted on a subface or a segment.
26280  break;
26281  }
26282  }
26283  } // if (!b->nobisect)
26284  encshlist->restart();
26285  if (splitflag) {
26286  // Some subfaces may need to be repaired.
26287  if (badsubfacs->items > 0) {
26288  repairencfacs(chkencflag | 2);
26289  }
26290  }
26291  } else {
26292  if (ivf.iloc == (int) NEARVERTEX) {
26293  terminatetetgen(this, 2);
26294  }
26295  }
26296  if (splitflag) {
26297  // Queue the tet if it is still alive.
26298  if ((splittet->tet != NULL) && (splittet->tet[4] != NULL)) {
26299  enqueuetetrahedron(splittet);
26300  }
26301  } else {
26302  //assert(0); // If no small angle, why can this happen?
26303  }
26304  return splitflag;
26305  }
26306 }
26307 
26309 // //
26310 // repairbadtets() Repair bad quality tetrahedra. //
26311 // //
26313 
26314 void tetgenmesh::repairbadtets(int chkencflag)
26315 {
26316  triface *bface;
26317  REAL ccent[3];
26318  int qflag = 0;
26319 
26320 
26321  // Loop until the pool 'badsubfacs' is empty. Note that steinerleft == -1
26322  // if an unlimited number of Steiner points is allowed.
26323  while ((badtetrahedrons->items > 0) && (steinerleft != 0)) {
26324  badtetrahedrons->traversalinit();
26325  bface = (triface *) badtetrahedrons->traverse();
26326  while ((bface != NULL) && (steinerleft != 0)) {
26327  // Skip a deleted element.
26328  if (bface->ver >= 0) {
26329  // A queued tet may have been deleted.
26330  if (!isdeadtet(*bface)) {
26331  // A queued tet may have been processed.
26332  if (marktest2ed(*bface)) {
26333  unmarktest2(*bface);
26334  if (checktet4split(bface, qflag, ccent)) {
26335  splittetrahedron(bface, qflag, ccent, chkencflag);
26336  }
26337  }
26338  }
26339  bface->ver = -1; // Signal it as a deleted element.
26340  badtetrahedrons->dealloc((void *) bface);
26341  }
26342  bface = (triface *) badtetrahedrons->traverse();
26343  }
26344  }
26345 
26346  if (badtetrahedrons->items > 0) {
26347  if (steinerleft == 0) {
26348  if (b->verbose) {
26349  printf("The desired number of Steiner points is reached.\n");
26350  }
26351  } else {
26352  terminatetetgen(this, 2); // Unknown case.
26353  }
26354  // Unmark all queued tet.
26355  badtetrahedrons->traversalinit();
26356  bface = (triface *) badtetrahedrons->traverse();
26357  while (bface != NULL) {
26358  // Skip a deleted element.
26359  if (bface->ver >= 0) {
26360  if (!isdeadtet(*bface)) {
26361  if (marktest2ed(*bface)) {
26362  unmarktest2(*bface);
26363  }
26364  }
26365  }
26366  bface = (triface *) badtetrahedrons->traverse();
26367  }
26368  // Clear the pool.
26369  badtetrahedrons->restart();
26370  }
26371 }
26372 
26374 // //
26375 // delaunayrefinement() Refine the mesh by Delaunay refinement. //
26376 // //
26378 
26379 void tetgenmesh::delaunayrefinement()
26380 {
26381  triface checktet;
26382  face checksh;
26383  face checkseg;
26384  long steinercount;
26385  int chkencflag;
26386 
26387  long bak_segref_count, bak_facref_count, bak_volref_count;
26388  long bak_flipcount = flip23count + flip32count + flip44count;
26389 
26390  if (!b->quiet) {
26391  printf("Refining mesh...\n");
26392  }
26393 
26394  if (b->verbose) {
26395  printf(" Min radius-edge ratio = %g.\n", b->minratio);
26396  printf(" Min dihedral angle = %g.\n", b->mindihedral);
26397  //printf(" Min Edge length = %g.\n", b->minedgelength);
26398  }
26399 
26400  steinerleft = b->steinerleft; // Upperbound of # Steiner points (by -S#).
26401  if (steinerleft > 0) {
26402  // Check if we've already used up the given number of Steiner points.
26403  steinercount = st_segref_count + st_facref_count + st_volref_count;
26404  if (steinercount < steinerleft) {
26405  steinerleft -= steinercount;
26406  } else {
26407  if (!b->quiet) {
26408  printf("\nWarning: ");
26409  printf("The desired number of Steiner points (%d) has reached.\n\n",
26410  b->steinerleft);
26411  }
26412  return; // No more Steiner points.
26413  }
26414  }
26415 
26416  if (useinsertradius) {
26417  if ((b->plc && b->nobisect) || b->refine) { // '-pY' or '-r' option.
26418  makesegmentendpointsmap();
26419  makefacetverticesmap();
26420  }
26421  }
26422 
26423 
26424  encseglist = new arraypool(sizeof(face), 8);
26425  encshlist = new arraypool(sizeof(badface), 8);
26426 
26427 
26428  //if (!b->nobisect) { // if no '-Y' option
26429  if (!b->nobisect || checkconstraints) {
26430  if (b->verbose) {
26431  printf(" Splitting encroached subsegments.\n");
26432  }
26433 
26434  chkencflag = 1; // Only check encroaching subsegments.
26435  steinercount = points->items;
26436 
26437  // Initialize the pool of encroached subsegments.
26438  badsubsegs = new memorypool(sizeof(face), b->shellfaceperblock,
26439  sizeof(void *), 0);
26440 
26441  // Add all segments into the pool.
26442  subsegs->traversalinit();
26443  checkseg.sh = shellfacetraverse(subsegs);
26444  while (checkseg.sh != (shellface *) NULL) {
26445  enqueuesubface(badsubsegs, &checkseg);
26446  checkseg.sh = shellfacetraverse(subsegs);
26447  }
26448 
26449  // Split all encroached segments.
26450  repairencsegs(chkencflag);
26451 
26452  if (b->verbose) {
26453  printf(" Added %ld Steiner points.\n", points->items - steinercount);
26454  }
26455 
26456  if (b->reflevel > 1) { // '-D2' option
26457  if (b->verbose) {
26458  printf(" Splitting encroached subfaces.\n");
26459  }
26460 
26461  chkencflag = 2; // Only check encroaching subfaces.
26462  steinercount = points->items;
26463  bak_segref_count = st_segref_count;
26464  bak_facref_count = st_facref_count;
26465 
26466  // Initialize the pool of encroached subfaces.
26467  badsubfacs = new memorypool(sizeof(face), b->shellfaceperblock,
26468  sizeof(void *), 0);
26469 
26470  // Add all subfaces into the pool.
26471  subfaces->traversalinit();
26472  checksh.sh = shellfacetraverse(subfaces);
26473  while (checksh.sh != (shellface *) NULL) {
26474  enqueuesubface(badsubfacs, &checksh);
26475  checksh.sh = shellfacetraverse(subfaces);
26476  }
26477 
26478  // Split all encroached subfaces.
26479  repairencfacs(chkencflag);
26480 
26481  if (b->verbose) {
26482  printf(" Added %ld (%ld,%ld) Steiner points.\n",
26483  points->items-steinercount, st_segref_count-bak_segref_count,
26484  st_facref_count-bak_facref_count);
26485  }
26486  } // if (b->reflevel > 1)
26487  } // if (!b->nobisect)
26488 
26489  if (b->reflevel > 2) { // '-D3' option (The default option)
26490  if (b->verbose) {
26491  printf(" Splitting bad quality tets.\n");
26492  }
26493 
26494  chkencflag = 4; // Only check tetrahedra.
26495  steinercount = points->items;
26496  bak_segref_count = st_segref_count;
26497  bak_facref_count = st_facref_count;
26498  bak_volref_count = st_volref_count;
26499 
26500  // The cosine value of the min dihedral angle (-qq) for tetrahedra.
26501  cosmindihed = cos(b->mindihedral / 180.0 * PI);
26502 
26503  // Initialize the pool of bad quality tetrahedra.
26504  badtetrahedrons = new memorypool(sizeof(triface), b->tetrahedraperblock,
26505  sizeof(void *), 0);
26506  // Add all tetrahedra (no hull tets) into the pool.
26507  tetrahedrons->traversalinit();
26508  checktet.tet = tetrahedrontraverse();
26509  while (checktet.tet != NULL) {
26510  enqueuetetrahedron(&checktet);
26511  checktet.tet = tetrahedrontraverse();
26512  }
26513 
26514  // Split all bad quality tetrahedra.
26515  repairbadtets(chkencflag);
26516 
26517  if (b->verbose) {
26518  printf(" Added %ld (%ld,%ld,%ld) Steiner points.\n",
26519  points->items - steinercount,
26520  st_segref_count - bak_segref_count,
26521  st_facref_count - bak_facref_count,
26522  st_volref_count - bak_volref_count);
26523  }
26524  } // if (b->reflevel > 2)
26525 
26526  if (b->verbose) {
26527  if (flip23count + flip32count + flip44count > bak_flipcount) {
26528  printf(" Performed %ld flips.\n", flip23count + flip32count +
26529  flip44count - bak_flipcount);
26530  }
26531  }
26532 
26533  if (steinerleft == 0) {
26534  if (!b->quiet) {
26535  printf("\nWarnning: ");
26536  printf("The desired number of Steiner points (%d) is reached.\n\n",
26537  b->steinerleft);
26538  }
26539  }
26540 
26541 
26542  delete encseglist;
26543  delete encshlist;
26544  encseglist = NULL;
26545  encshlist = NULL;
26546 
26547  if (!b->nobisect || checkconstraints) {
26548  totalworkmemory += (badsubsegs->maxitems * badsubsegs->itembytes);
26549  delete badsubsegs;
26550  badsubsegs = NULL;
26551  if (b->reflevel > 1) {
26552  totalworkmemory += (badsubfacs->maxitems * badsubfacs->itembytes);
26553  delete badsubfacs;
26554  badsubfacs = NULL;
26555  }
26556  }
26557  if (b->reflevel > 2) {
26558  totalworkmemory += (badtetrahedrons->maxitems*badtetrahedrons->itembytes);
26559  delete badtetrahedrons;
26560  badtetrahedrons = NULL;
26561  }
26562 }
26563 
26567 
26571 
26573 // //
26574 // lawsonflip3d() A three-dimensional Lawson's algorithm. //
26575 // //
26577 
26578 long tetgenmesh::lawsonflip3d(flipconstraints *fc)
26579 {
26580  triface fliptets[5], neightet, hulltet;
26581  face checksh, casingout;
26582  badface *popface, *bface;
26583  point pd, pe, *pts;
26584  REAL sign, ori;
26585  REAL vol, len3;
26586  long flipcount, totalcount = 0l;
26587  long sliver_peels = 0l;
26588  int t1ver;
26589  int i;
26590 
26591 
26592  while (1) {
26593 
26594  if (b->verbose > 2) {
26595  printf(" Lawson flip %ld faces.\n", flippool->items);
26596  }
26597  flipcount = 0l;
26598 
26599  while (flipstack != (badface *) NULL) {
26600  // Pop a face from the stack.
26601  popface = flipstack;
26602  fliptets[0] = popface->tt;
26603  flipstack = flipstack->nextitem; // The next top item in stack.
26604  flippool->dealloc((void *) popface);
26605 
26606  // Skip it if it is a dead tet (destroyed by previous flips).
26607  if (isdeadtet(fliptets[0])) continue;
26608  // Skip it if it is not the same tet as we saved.
26609  if (!facemarked(fliptets[0])) continue;
26610 
26611  unmarkface(fliptets[0]);
26612 
26613  if (ishulltet(fliptets[0])) continue;
26614 
26615  fsym(fliptets[0], fliptets[1]);
26616  if (ishulltet(fliptets[1])) {
26617  if (nonconvex) {
26618  // Check if 'fliptets[0]' it is a hull sliver.
26619  tspivot(fliptets[0], checksh);
26620  for (i = 0; i < 3; i++) {
26621  if (!isshsubseg(checksh)) {
26622  spivot(checksh, casingout);
26623  //assert(casingout.sh != NULL);
26624  if (sorg(checksh) != sdest(casingout)) sesymself(casingout);
26625  stpivot(casingout, neightet);
26626  if (neightet.tet == fliptets[0].tet) {
26627  // Found a hull sliver 'neightet'. Let it be [e,d,a,b], where
26628  // [e,d,a] and [d,e,b] are hull faces.
26629  edestoppo(neightet, hulltet); // [a,b,e,d]
26630  fsymself(hulltet); // [b,a,e,#]
26631  if (oppo(hulltet) == dummypoint) {
26632  pe = org(neightet);
26633  if ((pointtype(pe) == FREEFACETVERTEX) ||
26634  (pointtype(pe) == FREESEGVERTEX)) {
26635  removevertexbyflips(pe);
26636  }
26637  } else {
26638  eorgoppo(neightet, hulltet); // [b,a,d,e]
26639  fsymself(hulltet); // [a,b,d,#]
26640  if (oppo(hulltet) == dummypoint) {
26641  pd = dest(neightet);
26642  if ((pointtype(pd) == FREEFACETVERTEX) ||
26643  (pointtype(pd) == FREESEGVERTEX)) {
26644  removevertexbyflips(pd);
26645  }
26646  } else {
26647  // Perform a 3-to-2 flip to remove the sliver.
26648  fliptets[0] = neightet; // [e,d,a,b]
26649  fnext(fliptets[0], fliptets[1]); // [e,d,b,c]
26650  fnext(fliptets[1], fliptets[2]); // [e,d,c,a]
26651  flip32(fliptets, 1, fc);
26652  // Update counters.
26653  flip32count--;
26654  flip22count--;
26655  sliver_peels++;
26656  if (fc->remove_ndelaunay_edge) {
26657  // Update the volume (must be decreased).
26658  //assert(fc->tetprism_vol_sum <= 0);
26659  tetprism_vol_sum += fc->tetprism_vol_sum;
26660  fc->tetprism_vol_sum = 0.0; // Clear it.
26661  }
26662  }
26663  }
26664  break;
26665  } // if (neightet.tet == fliptets[0].tet)
26666  } // if (!isshsubseg(checksh))
26667  senextself(checksh);
26668  } // i
26669  } // if (nonconvex)
26670  continue;
26671  }
26672 
26673  if (checksubfaceflag) {
26674  // Do not flip if it is a subface.
26675  if (issubface(fliptets[0])) continue;
26676  }
26677 
26678  // Test whether the face is locally Delaunay or not.
26679  pts = (point *) fliptets[1].tet;
26680  sign = insphere_s(pts[4], pts[5], pts[6], pts[7], oppo(fliptets[0]));
26681 
26682  if (sign < 0) {
26683  // A non-Delaunay face. Try to flip it.
26684  pd = oppo(fliptets[0]);
26685  pe = oppo(fliptets[1]);
26686 
26687  // Use the length of the edge [d,e] as a reference to determine
26688  // a nearly degenerated new tet.
26689  len3 = distance(pd, pe);
26690  len3 = (len3 * len3 * len3);
26691  int round_flag = 0; // [2017-10-20]
26692  // Check the convexity of its three edges. Stop checking either a
26693  // locally non-convex edge (ori < 0) or a flat edge (ori = 0) is
26694  // encountered, and 'fliptet' represents that edge.
26695  for (i = 0; i < 3; i++) {
26696  ori = orient3d(org(fliptets[0]), dest(fliptets[0]), pd, pe);
26697  if (ori > 0) {
26698  // Avoid creating a nearly degenerated new tet at boundary.
26699  // Re-use fliptets[2], fliptets[3];
26700  esym(fliptets[0], fliptets[2]);
26701  esym(fliptets[1], fliptets[3]);
26702  if (issubface(fliptets[2]) || issubface(fliptets[3])) {
26703  vol = orient3dfast(org(fliptets[0]), dest(fliptets[0]), pd, pe);
26704  if ((fabs(vol) / len3) < b->epsilon) {
26705  ori = 0.0; // Do rounding.
26706  round_flag = 1; // [2017-10-20]
26707  }
26708  }
26709  } // Rounding check
26710  if (ori <= 0) break;
26711  enextself(fliptets[0]);
26712  eprevself(fliptets[1]);
26713  }
26714 
26715  if (ori > 0) {
26716  // A 2-to-3 flip is found.
26717  // [0] [a,b,c,d],
26718  // [1] [b,a,c,e]. no dummypoint.
26719  flip23(fliptets, 0, fc);
26720  flipcount++;
26721  if (fc->remove_ndelaunay_edge) {
26722  // Update the volume (must be decreased).
26723  //assert(fc->tetprism_vol_sum <= 0);
26724  tetprism_vol_sum += fc->tetprism_vol_sum;
26725  fc->tetprism_vol_sum = 0.0; // Clear it.
26726  }
26727  continue;
26728  } else { // ori <= 0
26729  // The edge ('fliptets[0]' = [a',b',c',d]) is non-convex or flat,
26730  // where the edge [a',b'] is one of [a,b], [b,c], and [c,a].
26731  if (checksubsegflag) {
26732  // Do not flip if it is a segment.
26733  if (issubseg(fliptets[0])) continue;
26734  }
26735  // Check if there are three or four tets sharing at this edge.
26736  esymself(fliptets[0]); // [b,a,d,c]
26737  for (i = 0; i < 3; i++) {
26738  fnext(fliptets[i], fliptets[i+1]);
26739  }
26740  if (fliptets[3].tet == fliptets[0].tet) {
26741  // A 3-to-2 flip is found. (No hull tet.)
26742  flip32(fliptets, 0, fc);
26743  flipcount++;
26744  if (fc->remove_ndelaunay_edge) {
26745  // Update the volume (must be decreased).
26746  //assert(fc->tetprism_vol_sum <= 0);
26747  tetprism_vol_sum += fc->tetprism_vol_sum;
26748  fc->tetprism_vol_sum = 0.0; // Clear it.
26749  }
26750  continue;
26751  } else {
26752  // There are more than 3 tets at this edge.
26753  fnext(fliptets[3], fliptets[4]);
26754  if (fliptets[4].tet == fliptets[0].tet) {
26755  // There are exactly 4 tets at this edge.
26756  if (round_flag == 1) {
26757  continue; // [2017-10-20]
26758  }
26759  if (nonconvex) {
26760  if (apex(fliptets[3]) == dummypoint) {
26761  // This edge is locally non-convex on the hull.
26762  // It can be removed by a 4-to-4 flip.
26763  ori = 0;
26764  }
26765  } // if (nonconvex)
26766  if (ori == 0) {
26767  // A 4-to-4 flip is found. (Two hull tets may be involved.)
26768  // Current tets in 'fliptets':
26769  // [0] [b,a,d,c] (d may be newpt)
26770  // [1] [b,a,c,e]
26771  // [2] [b,a,e,f] (f may be dummypoint)
26772  // [3] [b,a,f,d]
26773  esymself(fliptets[0]); // [a,b,c,d]
26774  // A 2-to-3 flip replaces face [a,b,c] by edge [e,d].
26775  // This creates a degenerate tet [e,d,a,b] (tmpfliptets[0]).
26776  // It will be removed by the followed 3-to-2 flip.
26777  flip23(fliptets, 0, fc); // No hull tet.
26778  fnext(fliptets[3], fliptets[1]);
26779  fnext(fliptets[1], fliptets[2]);
26780  // Current tets in 'fliptets':
26781  // [0] [...]
26782  // [1] [b,a,d,e] (degenerated, d may be new point).
26783  // [2] [b,a,e,f] (f may be dummypoint)
26784  // [3] [b,a,f,d]
26785  // A 3-to-2 flip replaces edge [b,a] by face [d,e,f].
26786  // Hull tets may be involved (f may be dummypoint).
26787  flip32(&(fliptets[1]), (apex(fliptets[3]) == dummypoint), fc);
26788  flipcount++;
26789  flip23count--;
26790  flip32count--;
26791  flip44count++;
26792  if (fc->remove_ndelaunay_edge) {
26793  // Update the volume (must be decreased).
26794  //assert(fc->tetprism_vol_sum <= 0);
26795  tetprism_vol_sum += fc->tetprism_vol_sum;
26796  fc->tetprism_vol_sum = 0.0; // Clear it.
26797  }
26799  //if (checkmesh(0) > 0) {
26800  // assert(0);
26801  //}
26802  continue;
26803  } // if (ori == 0)
26804  }
26805  }
26806  } // if (ori <= 0)
26807 
26808  // This non-Delaunay face is unflippable. Save it.
26809  unflipqueue->newindex((void **) &bface);
26810  bface->tt = fliptets[0];
26811  bface->forg = org(fliptets[0]);
26812  bface->fdest = dest(fliptets[0]);
26813  bface->fapex = apex(fliptets[0]);
26814  } // if (sign < 0)
26815  } // while (flipstack)
26816 
26817  if (b->verbose > 2) {
26818  if (flipcount > 0) {
26819  printf(" Performed %ld flips.\n", flipcount);
26820  }
26821  }
26822  // Accumulate the counter of flips.
26823  totalcount += flipcount;
26824 
26825  // Return if no unflippable faces left.
26826  if (unflipqueue->objects == 0l) break;
26827  // Return if no flip has been performed.
26828  if (flipcount == 0l) break;
26829 
26830  // Try to flip the unflippable faces.
26831  for (i = 0; i < unflipqueue->objects; i++) {
26832  bface = (badface *) fastlookup(unflipqueue, i);
26833  if (!isdeadtet(bface->tt) &&
26834  (org(bface->tt) == bface->forg) &&
26835  (dest(bface->tt) == bface->fdest) &&
26836  (apex(bface->tt) == bface->fapex)) {
26837  flippush(flipstack, &(bface->tt));
26838  }
26839  }
26840  unflipqueue->restart();
26841 
26842  } // while (1)
26843 
26844  if (b->verbose > 2) {
26845  if (totalcount > 0) {
26846  printf(" Performed %ld flips.\n", totalcount);
26847  }
26848  if (sliver_peels > 0) {
26849  printf(" Removed %ld hull slivers.\n", sliver_peels);
26850  }
26851  if (unflipqueue->objects > 0l) {
26852  printf(" %ld unflippable edges remained.\n", unflipqueue->objects);
26853  }
26854  }
26855 
26856  return totalcount + sliver_peels;
26857 }
26858 
26860 // //
26861 // recoverdelaunay() Recovery the locally Delaunay property. //
26862 // //
26864 
26865 void tetgenmesh::recoverdelaunay()
26866 {
26867  arraypool *flipqueue, *nextflipqueue, *swapqueue;
26868  triface tetloop, neightet, *parytet;
26869  badface *bface, *parybface;
26870  point *ppt;
26871  flipconstraints fc;
26872  int i, j;
26873 
26874  if (!b->quiet) {
26875  printf("Recovering Delaunayness...\n");
26876  }
26877 
26878  tetprism_vol_sum = 0.0; // Initialize it.
26879 
26880  // Put all interior faces of the mesh into 'flipstack'.
26881  tetrahedrons->traversalinit();
26882  tetloop.tet = tetrahedrontraverse();
26883  while (tetloop.tet != NULL) {
26884  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
26885  decode(tetloop.tet[tetloop.ver], neightet);
26886  if (!facemarked(neightet)) {
26887  flippush(flipstack, &tetloop);
26888  }
26889  }
26890  ppt = (point *) &(tetloop.tet[4]);
26891  tetprism_vol_sum += tetprismvol(ppt[0], ppt[1], ppt[2], ppt[3]);
26892  tetloop.tet = tetrahedrontraverse();
26893  }
26894 
26895  // Calulate a relatively lower bound for small improvement.
26896  // Used to avoid rounding error in volume calculation.
26897  fc.bak_tetprism_vol = tetprism_vol_sum * b->epsilon * 1e-3;
26898 
26899  if (b->verbose) {
26900  printf(" Initial obj = %.17g\n", tetprism_vol_sum);
26901  }
26902 
26903  if (b->verbose > 1) {
26904  printf(" Recover Delaunay [Lawson] : %ld\n", flippool->items);
26905  }
26906 
26907  // First only use the basic Lawson's flip.
26908  fc.remove_ndelaunay_edge = 1;
26909  fc.enqflag = 2;
26910 
26911  lawsonflip3d(&fc);
26912 
26913  if (b->verbose > 1) {
26914  printf(" obj (after Lawson) = %.17g\n", tetprism_vol_sum);
26915  }
26916 
26917  if (unflipqueue->objects == 0l) {
26918  return; // The mesh is Delaunay.
26919  }
26920 
26921  fc.unflip = 1; // Unflip if the edge is not flipped.
26922  fc.collectnewtets = 1; // new tets are returned in 'cavetetlist'.
26923  fc.enqflag = 0;
26924 
26925  autofliplinklevel = 1; // Init level.
26926  b->fliplinklevel = -1; // No fixed level.
26927 
26928  // For efficiency reason, we limit the maximium size of the edge star.
26929  int bakmaxflipstarsize = b->flipstarsize;
26930  b->flipstarsize = 10; // default
26931 
26932  flipqueue = new arraypool(sizeof(badface), 10);
26933  nextflipqueue = new arraypool(sizeof(badface), 10);
26934 
26935  // Swap the two flip queues.
26936  swapqueue = flipqueue;
26937  flipqueue = unflipqueue;
26938  unflipqueue = swapqueue;
26939 
26940  while (flipqueue->objects > 0l) {
26941 
26942  if (b->verbose > 1) {
26943  printf(" Recover Delaunay [level = %2d] #: %ld.\n",
26944  autofliplinklevel, flipqueue->objects);
26945  }
26946 
26947  for (i = 0; i < flipqueue->objects; i++) {
26948  bface = (badface *) fastlookup(flipqueue, i);
26949  if (getedge(bface->forg, bface->fdest, &bface->tt)) {
26950  if (removeedgebyflips(&(bface->tt), &fc) == 2) {
26951  tetprism_vol_sum += fc.tetprism_vol_sum;
26952  fc.tetprism_vol_sum = 0.0; // Clear it.
26953  // Queue new faces for flips.
26954  for (j = 0; j < cavetetlist->objects; j++) {
26955  parytet = (triface *) fastlookup(cavetetlist, j);
26956  // A queued new tet may be dead.
26957  if (!isdeadtet(*parytet)) {
26958  for (parytet->ver = 0; parytet->ver < 4; parytet->ver++) {
26959  // Avoid queue a face twice.
26960  decode(parytet->tet[parytet->ver], neightet);
26961  if (!facemarked(neightet)) {
26962  flippush(flipstack, parytet);
26963  }
26964  } // parytet->ver
26965  }
26966  } // j
26967  cavetetlist->restart();
26968  // Remove locally non-Delaunay faces. New non-Delaunay edges
26969  // may be found. They are saved in 'unflipqueue'.
26970  fc.enqflag = 2;
26971  lawsonflip3d(&fc);
26972  fc.enqflag = 0;
26973  // There may be unflipable faces. Add them in flipqueue.
26974  for (j = 0; j < unflipqueue->objects; j++) {
26975  bface = (badface *) fastlookup(unflipqueue, j);
26976  flipqueue->newindex((void **) &parybface);
26977  *parybface = *bface;
26978  }
26979  unflipqueue->restart();
26980  } else {
26981  // Unable to remove this edge. Save it.
26982  nextflipqueue->newindex((void **) &parybface);
26983  *parybface = *bface;
26984  // Normally, it should be zero.
26985  //assert(fc.tetprism_vol_sum == 0.0);
26986  // However, due to rounding errors, a tiny value may appear.
26987  fc.tetprism_vol_sum = 0.0;
26988  }
26989  }
26990  } // i
26991 
26992  if (b->verbose > 1) {
26993  printf(" obj (after level %d) = %.17g.\n", autofliplinklevel,
26994  tetprism_vol_sum);
26995  }
26996  flipqueue->restart();
26997 
26998  // Swap the two flip queues.
26999  swapqueue = flipqueue;
27000  flipqueue = nextflipqueue;
27001  nextflipqueue = swapqueue;
27002 
27003  if (flipqueue->objects > 0l) {
27004  // default 'b->delmaxfliplevel' is 1.
27005  if (autofliplinklevel >= b->delmaxfliplevel) {
27006  // For efficiency reason, we do not search too far.
27007  break;
27008  }
27009  autofliplinklevel+=b->fliplinklevelinc;
27010  }
27011  } // while (flipqueue->objects > 0l)
27012 
27013  if (flipqueue->objects > 0l) {
27014  if (b->verbose > 1) {
27015  printf(" %ld non-Delaunay edges remained.\n", flipqueue->objects);
27016  }
27017  }
27018 
27019  if (b->verbose) {
27020  printf(" Final obj = %.17g\n", tetprism_vol_sum);
27021  }
27022 
27023  b->flipstarsize = bakmaxflipstarsize;
27024  delete flipqueue;
27025  delete nextflipqueue;
27026 }
27027 
27029 // //
27030 // gettetrahedron() Get a tetrahedron which have the given vertices. //
27031 // //
27033 
27034 int tetgenmesh::gettetrahedron(point pa, point pb, point pc, point pd,
27035  triface *searchtet)
27036 {
27037  triface spintet;
27038  int t1ver;
27039 
27040  if (getedge(pa, pb, searchtet)) {
27041  spintet = *searchtet;
27042  while (1) {
27043  if (apex(spintet) == pc) {
27044  *searchtet = spintet;
27045  break;
27046  }
27047  fnextself(spintet);
27048  if (spintet.tet == searchtet->tet) break;
27049  }
27050  if (apex(*searchtet) == pc) {
27051  if (oppo(*searchtet) == pd) {
27052  return 1;
27053  } else {
27054  fsymself(*searchtet);
27055  if (oppo(*searchtet) == pd) {
27056  return 1;
27057  }
27058  }
27059  }
27060  }
27061 
27062  return 0;
27063 }
27064 
27066 // //
27067 // improvequalitybyflips() Improve the mesh quality by flips. //
27068 // //
27070 
27071 long tetgenmesh::improvequalitybyflips()
27072 {
27073  arraypool *flipqueue, *nextflipqueue, *swapqueue;
27074  badface *bface, *parybface;
27075  triface *parytet;
27076  point *ppt;
27077  flipconstraints fc;
27078  REAL *cosdd, ncosdd[6], maxdd;
27079  long totalremcount, remcount;
27080  int remflag;
27081  int n, i, j, k;
27082 
27083  //assert(unflipqueue->objects > 0l);
27084  flipqueue = new arraypool(sizeof(badface), 10);
27085  nextflipqueue = new arraypool(sizeof(badface), 10);
27086 
27087  // Backup flip edge options.
27088  int bakautofliplinklevel = autofliplinklevel;
27089  int bakfliplinklevel = b->fliplinklevel;
27090  int bakmaxflipstarsize = b->flipstarsize;
27091 
27092  // Set flip edge options.
27093  autofliplinklevel = 1;
27094  b->fliplinklevel = -1;
27095  b->flipstarsize = 10; // b->optmaxflipstarsize;
27096 
27097  fc.remove_large_angle = 1;
27098  fc.unflip = 1;
27099  fc.collectnewtets = 1;
27100  fc.checkflipeligibility = 1;
27101 
27102  totalremcount = 0l;
27103 
27104  // Swap the two flip queues.
27105  swapqueue = flipqueue;
27106  flipqueue = unflipqueue;
27107  unflipqueue = swapqueue;
27108 
27109  while (flipqueue->objects > 0l) {
27110 
27111  remcount = 0l;
27112 
27113  while (flipqueue->objects > 0l) {
27114  if (b->verbose > 1) {
27115  printf(" Improving mesh qualiy by flips [%d]#: %ld.\n",
27116  autofliplinklevel, flipqueue->objects);
27117  }
27118 
27119  for (k = 0; k < flipqueue->objects; k++) {
27120  bface = (badface *) fastlookup(flipqueue, k);
27121  if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
27122  bface->foppo, &bface->tt)) {
27123  //assert(!ishulltet(bface->tt));
27124  // There are bad dihedral angles in this tet.
27125  if (bface->tt.ver != 11) {
27126  // The dihedral angles are permuted.
27127  // Here we simply re-compute them. Slow!!.
27128  ppt = (point *) & (bface->tt.tet[4]);
27129  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
27130  &bface->key, NULL);
27131  bface->forg = ppt[0];
27132  bface->fdest = ppt[1];
27133  bface->fapex = ppt[2];
27134  bface->foppo = ppt[3];
27135  bface->tt.ver = 11;
27136  }
27137  if (bface->key == 0) {
27138  // Re-comput the quality values. Due to smoothing operations.
27139  ppt = (point *) & (bface->tt.tet[4]);
27140  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
27141  &bface->key, NULL);
27142  }
27143  cosdd = bface->cent;
27144  remflag = 0;
27145  for (i = 0; (i < 6) && !remflag; i++) {
27146  if (cosdd[i] < cosmaxdihed) {
27147  // Found a large dihedral angle.
27148  bface->tt.ver = edge2ver[i]; // Go to the edge.
27149  fc.cosdihed_in = cosdd[i];
27150  fc.cosdihed_out = 0.0; // 90 degree.
27151  n = removeedgebyflips(&(bface->tt), &fc);
27152  if (n == 2) {
27153  // Edge is flipped.
27154  remflag = 1;
27155  if (fc.cosdihed_out < cosmaxdihed) {
27156  // Queue new bad tets for further improvements.
27157  for (j = 0; j < cavetetlist->objects; j++) {
27158  parytet = (triface *) fastlookup(cavetetlist, j);
27159  if (!isdeadtet(*parytet)) {
27160  ppt = (point *) & (parytet->tet[4]);
27161  // Do not test a hull tet.
27162  if (ppt[3] != dummypoint) {
27163  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd,
27164  &maxdd, NULL);
27165  if (maxdd < cosmaxdihed) {
27166  // There are bad dihedral angles in this tet.
27167  nextflipqueue->newindex((void **) &parybface);
27168  parybface->tt.tet = parytet->tet;
27169  parybface->tt.ver = 11;
27170  parybface->forg = ppt[0];
27171  parybface->fdest = ppt[1];
27172  parybface->fapex = ppt[2];
27173  parybface->foppo = ppt[3];
27174  parybface->key = maxdd;
27175  for (n = 0; n < 6; n++) {
27176  parybface->cent[n] = ncosdd[n];
27177  }
27178  }
27179  } // if (ppt[3] != dummypoint)
27180  }
27181  } // j
27182  } // if (fc.cosdihed_out < cosmaxdihed)
27183  cavetetlist->restart();
27184  remcount++;
27185  }
27186  }
27187  } // i
27188  if (!remflag) {
27189  // An unremoved bad tet. Queue it again.
27190  unflipqueue->newindex((void **) &parybface);
27191  *parybface = *bface;
27192  }
27193  } // if (gettetrahedron(...))
27194  } // k
27195 
27196  flipqueue->restart();
27197 
27198  // Swap the two flip queues.
27199  swapqueue = flipqueue;
27200  flipqueue = nextflipqueue;
27201  nextflipqueue = swapqueue;
27202  } // while (flipqueues->objects > 0)
27203 
27204  if (b->verbose > 1) {
27205  printf(" Removed %ld bad tets.\n", remcount);
27206  }
27207  totalremcount += remcount;
27208 
27209  if (unflipqueue->objects > 0l) {
27210  //if (autofliplinklevel >= b->optmaxfliplevel) {
27211  if (autofliplinklevel >= b->optlevel) {
27212  break;
27213  }
27214  autofliplinklevel+=b->fliplinklevelinc;
27215  //b->flipstarsize = 10 + (1 << (b->optlevel - 1));
27216  }
27217 
27218  // Swap the two flip queues.
27219  swapqueue = flipqueue;
27220  flipqueue = unflipqueue;
27221  unflipqueue = swapqueue;
27222  } // while (flipqueues->objects > 0)
27223 
27224  // Restore original flip edge options.
27225  autofliplinklevel = bakautofliplinklevel;
27226  b->fliplinklevel = bakfliplinklevel;
27227  b->flipstarsize = bakmaxflipstarsize;
27228 
27229  delete flipqueue;
27230  delete nextflipqueue;
27231 
27232  return totalremcount;
27233 }
27234 
27236 // //
27237 // smoothpoint() Moving a vertex to improve the mesh quality. //
27238 // //
27239 // 'smtpt' (p) is a point to be smoothed. Generally, it is a Steiner point. //
27240 // It may be not a vertex of the mesh. //
27241 // //
27242 // This routine tries to move 'p' inside its star until a selected objective //
27243 // function over all tetrahedra in the star is improved. The function may be //
27244 // the some quality measures, i.e., aspect ratio, maximum dihedral angel, or //
27245 // simply the volume of the tetrahedra. //
27246 // //
27247 // 'linkfacelist' contains the list of link faces of 'p'. Since a link face //
27248 // has two orientations, ccw or cw, with respect to 'p'. 'ccw' indicates //
27249 // the orientation is ccw (1) or not (0). //
27250 // //
27251 // 'opm' is a structure contains the parameters of the objective function. //
27252 // It is needed by the evaluation of the function value. //
27253 // //
27254 // The return value indicates weather the point is smoothed or not. //
27255 // //
27256 // ASSUMPTION: This routine assumes that all link faces are true faces, i.e, //
27257 // no face has 'dummypoint' as its vertex. //
27258 // //
27260 
27261 int tetgenmesh::smoothpoint(point smtpt, arraypool *linkfacelist, int ccw,
27262  optparameters *opm)
27263 {
27264  triface *parytet, *parytet1, swaptet;
27265  point pa, pb, pc;
27266  REAL fcent[3], startpt[3], nextpt[3], bestpt[3];
27267  REAL oldval, minval = 0.0, val;
27268  REAL maxcosd; // oldang, newang;
27269  REAL ori, diff;
27270  int numdirs, iter;
27271  int i, j, k;
27272 
27273  // Decide the number of moving directions.
27274  numdirs = (int) linkfacelist->objects;
27275  if (numdirs > opm->numofsearchdirs) {
27276  numdirs = opm->numofsearchdirs; // Maximum search directions.
27277  }
27278 
27279  // Set the initial value.
27280  opm->imprval = opm->initval;
27281  iter = 0;
27282 
27283  for (i = 0; i < 3; i++) {
27284  bestpt[i] = startpt[i] = smtpt[i];
27285  }
27286 
27287  // Iterate until the obj function is not improved.
27288  while (1) {
27289 
27290  // Find the best next location.
27291  oldval = opm->imprval;
27292 
27293  for (i = 0; i < numdirs; i++) {
27294  // Randomly pick a link face (0 <= k <= objects - i - 1).
27295  k = (int) randomnation(linkfacelist->objects - i);
27296  parytet = (triface *) fastlookup(linkfacelist, k);
27297  // Calculate a new position from 'p' to the center of this face.
27298  pa = org(*parytet);
27299  pb = dest(*parytet);
27300  pc = apex(*parytet);
27301  for (j = 0; j < 3; j++) {
27302  fcent[j] = (pa[j] + pb[j] + pc[j]) / 3.0;
27303  }
27304  for (j = 0; j < 3; j++) {
27305  nextpt[j] = startpt[j] + opm->searchstep * (fcent[j] - startpt[j]);
27306  }
27307  // Calculate the largest minimum function value for the new location.
27308  for (j = 0; j < linkfacelist->objects; j++) {
27309  parytet = (triface *) fastlookup(linkfacelist, j);
27310  if (ccw) {
27311  pa = org(*parytet);
27312  pb = dest(*parytet);
27313  } else {
27314  pb = org(*parytet);
27315  pa = dest(*parytet);
27316  }
27317  pc = apex(*parytet);
27318  ori = orient3d(pa, pb, pc, nextpt);
27319  if (ori < 0.0) {
27320  // Calcuate the objective function value.
27321  if (opm->max_min_volume) {
27322  //val = -ori;
27323  val = - orient3dfast(pa, pb, pc, nextpt);
27324  } else if (opm->min_max_aspectratio) {
27325  val = 1.0 / tetaspectratio(pa, pb, pc, nextpt);
27326  } else if (opm->min_max_dihedangle) {
27327  tetalldihedral(pa, pb, pc, nextpt, NULL, &maxcosd, NULL);
27328  if (maxcosd < -1) maxcosd = -1.0; // Rounding.
27329  val = maxcosd + 1.0; // Make it be positive.
27330  } else {
27331  // Unknown objective function.
27332  val = 0.0;
27333  }
27334  } else { // ori >= 0.0;
27335  // An invalid new tet.
27336  // This may happen if the mesh contains inverted elements.
27337  if (opm->max_min_volume) {
27338  //val = -ori;
27339  val = - orient3dfast(pa, pb, pc, nextpt);
27340  } else {
27341  // Discard this point.
27342  break; // j
27343  }
27344  } // if (ori >= 0.0)
27345  // Stop looping when the object value is not improved.
27346  if (val <= opm->imprval) {
27347  break; // j
27348  } else {
27349  // Remember the smallest improved value.
27350  if (j == 0) {
27351  minval = val;
27352  } else {
27353  minval = (val < minval) ? val : minval;
27354  }
27355  }
27356  } // j
27357  if (j == linkfacelist->objects) {
27358  // The function value has been improved.
27359  opm->imprval = minval;
27360  // Save the new location of the point.
27361  for (j = 0; j < 3; j++) bestpt[j] = nextpt[j];
27362  }
27363  // Swap k-th and (object-i-1)-th entries.
27364  j = linkfacelist->objects - i - 1;
27365  parytet = (triface *) fastlookup(linkfacelist, k);
27366  parytet1 = (triface *) fastlookup(linkfacelist, j);
27367  swaptet = *parytet1;
27368  *parytet1 = *parytet;
27369  *parytet = swaptet;
27370  } // i
27371 
27372  diff = opm->imprval - oldval;
27373  if (diff > 0.0) {
27374  // Is the function value improved effectively?
27375  if (opm->max_min_volume) {
27376  //if ((diff / oldval) < b->epsilon) diff = 0.0;
27377  } else if (opm->min_max_aspectratio) {
27378  if ((diff / oldval) < 1e-3) diff = 0.0;
27379  } else if (opm->min_max_dihedangle) {
27380  //oldang = acos(oldval - 1.0);
27381  //newang = acos(opm->imprval - 1.0);
27382  //if ((oldang - newang) < 0.00174) diff = 0.0; // about 0.1 degree.
27383  } else {
27384  // Unknown objective function.
27385  terminatetetgen(this, 2);
27386  }
27387  }
27388 
27389  if (diff > 0.0) {
27390  // Yes, move p to the new location and continue.
27391  for (j = 0; j < 3; j++) startpt[j] = bestpt[j];
27392  iter++;
27393  if ((opm->maxiter > 0) && (iter >= opm->maxiter)) {
27394  // Maximum smoothing iterations reached.
27395  break;
27396  }
27397  } else {
27398  break;
27399  }
27400 
27401  } // while (1)
27402 
27403  if (iter > 0) {
27404  // The point has been smoothed.
27405  opm->smthiter = iter; // Remember the number of iterations.
27406  // The point has been smoothed. Update it to its new position.
27407  for (i = 0; i < 3; i++) smtpt[i] = startpt[i];
27408  }
27409 
27410  return iter;
27411 }
27412 
27413 
27415 // //
27416 // improvequalitysmoothing() Improve mesh quality by smoothing. //
27417 // //
27419 
27420 long tetgenmesh::improvequalitybysmoothing(optparameters *opm)
27421 {
27422  arraypool *flipqueue, *swapqueue;
27423  triface *parytet;
27424  badface *bface, *parybface;
27425  point *ppt;
27426  long totalsmtcount, smtcount;
27427  int smtflag;
27428  int iter, i, j, k;
27429 
27430  //assert(unflipqueue->objects > 0l);
27431  flipqueue = new arraypool(sizeof(badface), 10);
27432 
27433  // Swap the two flip queues.
27434  swapqueue = flipqueue;
27435  flipqueue = unflipqueue;
27436  unflipqueue = swapqueue;
27437 
27438  totalsmtcount = 0l;
27439  iter = 0;
27440 
27441  while (flipqueue->objects > 0l) {
27442 
27443  smtcount = 0l;
27444 
27445  if (b->verbose > 1) {
27446  printf(" Improving mesh quality by smoothing [%d]#: %ld.\n",
27447  iter, flipqueue->objects);
27448  }
27449 
27450  for (k = 0; k < flipqueue->objects; k++) {
27451  bface = (badface *) fastlookup(flipqueue, k);
27452  if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
27453  bface->foppo, &bface->tt)) {
27454  // Operate on it if it is not in 'unflipqueue'.
27455  if (!marktested(bface->tt)) {
27456  // Here we simply re-compute the quality. Since other smoothing
27457  // operation may have moved the vertices of this tet.
27458  ppt = (point *) & (bface->tt.tet[4]);
27459  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
27460  &bface->key, NULL);
27461  if (bface->key < cossmtdihed) { // if (maxdd < cosslidihed) {
27462  // It is a sliver. Try to smooth its vertices.
27463  smtflag = 0;
27464  opm->initval = bface->key + 1.0;
27465  for (i = 0; (i < 4) && !smtflag; i++) {
27466  if (pointtype(ppt[i]) == FREEVOLVERTEX) {
27467  getvertexstar(1, ppt[i], cavetetlist, NULL, NULL);
27468  opm->searchstep = 0.001; // Search step size
27469  smtflag = smoothpoint(ppt[i], cavetetlist, 1, opm);
27470  if (smtflag) {
27471  while (opm->smthiter == opm->maxiter) {
27472  opm->searchstep *= 10.0; // Increase the step size.
27473  opm->initval = opm->imprval;
27474  opm->smthiter = 0; // reset
27475  smoothpoint(ppt[i], cavetetlist, 1, opm);
27476  }
27477  // This tet is modifed.
27478  smtcount++;
27479  if ((opm->imprval - 1.0) < cossmtdihed) {
27480  // There are slivers in new tets. Queue them.
27481  for (j = 0; j < cavetetlist->objects; j++) {
27482  parytet = (triface *) fastlookup(cavetetlist, j);
27483  // Operate it if it is not in 'unflipqueue'.
27484  if (!marktested(*parytet)) {
27485  // Evaluate its quality.
27486  // Re-use ppt, bface->key, bface->cent.
27487  ppt = (point *) & (parytet->tet[4]);
27488  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3],
27489  bface->cent, &bface->key, NULL);
27490  if (bface->key < cossmtdihed) {
27491  // A new sliver. Queue it.
27492  marktest(*parytet); // It is in unflipqueue.
27493  unflipqueue->newindex((void **) &parybface);
27494  parybface->tt = *parytet;
27495  parybface->forg = ppt[0];
27496  parybface->fdest = ppt[1];
27497  parybface->fapex = ppt[2];
27498  parybface->foppo = ppt[3];
27499  parybface->tt.ver = 11;
27500  parybface->key = 0.0;
27501  }
27502  }
27503  } // j
27504  } // if ((opm->imprval - 1.0) < cossmtdihed)
27505  } // if (smtflag)
27506  cavetetlist->restart();
27507  } // if (pointtype(ppt[i]) == FREEVOLVERTEX)
27508  } // i
27509  if (!smtflag) {
27510  // Didn't smooth. Queue it again.
27511  marktest(bface->tt); // It is in unflipqueue.
27512  unflipqueue->newindex((void **) &parybface);
27513  parybface->tt = bface->tt;
27514  parybface->forg = ppt[0];
27515  parybface->fdest = ppt[1];
27516  parybface->fapex = ppt[2];
27517  parybface->foppo = ppt[3];
27518  parybface->tt.ver = 11;
27519  parybface->key = 0.0;
27520  }
27521  } // if (maxdd < cosslidihed)
27522  } // if (!marktested(...))
27523  } // if (gettetrahedron(...))
27524  } // k
27525 
27526  flipqueue->restart();
27527 
27528  // Unmark the tets in unflipqueue.
27529  for (i = 0; i < unflipqueue->objects; i++) {
27530  bface = (badface *) fastlookup(unflipqueue, i);
27531  unmarktest(bface->tt);
27532  }
27533 
27534  if (b->verbose > 1) {
27535  printf(" Smooth %ld points.\n", smtcount);
27536  }
27537  totalsmtcount += smtcount;
27538 
27539  if (smtcount == 0l) {
27540  // No point has been smoothed.
27541  break;
27542  } else {
27543  iter++;
27544  if (iter == 2) { //if (iter >= b->optpasses) {
27545  break;
27546  }
27547  }
27548 
27549  // Swap the two flip queues.
27550  swapqueue = flipqueue;
27551  flipqueue = unflipqueue;
27552  unflipqueue = swapqueue;
27553  } // while
27554 
27555  delete flipqueue;
27556 
27557  return totalsmtcount;
27558 }
27559 
27561 // //
27562 // splitsliver() Split a sliver. //
27563 // //
27565 
27566 int tetgenmesh::splitsliver(triface *slitet, REAL cosd, int chkencflag)
27567 {
27568  triface *abtets;
27569  triface searchtet, spintet, *parytet;
27570  point pa, pb, steinerpt;
27571  optparameters opm;
27572  insertvertexflags ivf;
27573  REAL smtpt[3], midpt[3];
27574  int success;
27575  int t1ver;
27576  int n, i;
27577 
27578  // 'slitet' is [c,d,a,b], where [c,d] has a big dihedral angle.
27579  // Go to the opposite edge [a,b].
27580  edestoppo(*slitet, searchtet); // [a,b,c,d].
27581 
27582  // Do not split a segment.
27583  if (issubseg(searchtet)) {
27584  return 0;
27585  }
27586 
27587  // Count the number of tets shared at [a,b].
27588  // Do not split it if it is a hull edge.
27589  spintet = searchtet;
27590  n = 0;
27591  while (1) {
27592  if (ishulltet(spintet)) break;
27593  n++;
27594  fnextself(spintet);
27595  if (spintet.tet == searchtet.tet) break;
27596  }
27597  if (ishulltet(spintet)) {
27598  return 0; // It is a hull edge.
27599  }
27600 
27601  // Get all tets at edge [a,b].
27602  abtets = new triface[n];
27603  spintet = searchtet;
27604  for (i = 0; i < n; i++) {
27605  abtets[i] = spintet;
27606  fnextself(spintet);
27607  }
27608 
27609  // Initialize the list of 2n boundary faces.
27610  for (i = 0; i < n; i++) {
27611  eprev(abtets[i], searchtet);
27612  esymself(searchtet); // [a,p_i,p_i+1].
27613  cavetetlist->newindex((void **) &parytet);
27614  *parytet = searchtet;
27615  enext(abtets[i], searchtet);
27616  esymself(searchtet); // [p_i,b,p_i+1].
27617  cavetetlist->newindex((void **) &parytet);
27618  *parytet = searchtet;
27619  }
27620 
27621  // Init the Steiner point at the midpoint of edge [a,b].
27622  pa = org(abtets[0]);
27623  pb = dest(abtets[0]);
27624  for (i = 0; i < 3; i++) {
27625  smtpt[i] = midpt[i] = 0.5 * (pa[i] + pb[i]);
27626  }
27627 
27628  // Point smooth options.
27629  opm.min_max_dihedangle = 1;
27630  opm.initval = cosd + 1.0; // Initial volume is zero.
27631  opm.numofsearchdirs = 20;
27632  opm.searchstep = 0.001;
27633  opm.maxiter = 100; // Limit the maximum iterations.
27634 
27635  success = smoothpoint(smtpt, cavetetlist, 1, &opm);
27636 
27637  if (success) {
27638  while (opm.smthiter == opm.maxiter) {
27639  // It was relocated and the prescribed maximum iteration reached.
27640  // Try to increase the search stepsize.
27641  opm.searchstep *= 10.0;
27642  //opm.maxiter = 100; // Limit the maximum iterations.
27643  opm.initval = opm.imprval;
27644  opm.smthiter = 0; // Init.
27645  smoothpoint(smtpt, cavetetlist, 1, &opm);
27646  }
27647  } // if (success)
27648 
27649  cavetetlist->restart();
27650 
27651  if (!success) {
27652  delete [] abtets;
27653  return 0;
27654  }
27655 
27656 
27657  // Insert the Steiner point.
27658  makepoint(&steinerpt, FREEVOLVERTEX);
27659  for (i = 0; i < 3; i++) steinerpt[i] = smtpt[i];
27660 
27661  // Insert the created Steiner point.
27662  for (i = 0; i < n; i++) {
27663  infect(abtets[i]);
27664  caveoldtetlist->newindex((void **) &parytet);
27665  *parytet = abtets[i];
27666  }
27667 
27668  searchtet = abtets[0]; // No need point location.
27669  if (b->metric) {
27670  locate(steinerpt, &searchtet); // For size interpolation.
27671  }
27672 
27673  delete [] abtets;
27674 
27675  ivf.iloc = (int) INSTAR;
27676  ivf.chkencflag = chkencflag;
27677  ivf.assignmeshsize = b->metric;
27678 
27679 
27680  if (insertpoint(steinerpt, &searchtet, NULL, NULL, &ivf)) {
27681  // The vertex has been inserted.
27682  st_volref_count++;
27683  if (steinerleft > 0) steinerleft--;
27684  return 1;
27685  } else {
27686  // The Steiner point is too close to an existing vertex. Reject it.
27687  pointdealloc(steinerpt);
27688  return 0;
27689  }
27690 }
27691 
27693 // //
27694 // removeslivers() Remove slivers by adding Steiner points. //
27695 // //
27697 
27698 long tetgenmesh::removeslivers(int chkencflag)
27699 {
27700  arraypool *flipqueue, *swapqueue;
27701  badface *bface, *parybface;
27702  triface slitet, *parytet;
27703  point *ppt;
27704  REAL cosdd[6], maxcosd;
27705  long totalsptcount, sptcount;
27706  int iter, i, j, k;
27707 
27708  //assert(unflipqueue->objects > 0l);
27709  flipqueue = new arraypool(sizeof(badface), 10);
27710 
27711  // Swap the two flip queues.
27712  swapqueue = flipqueue;
27713  flipqueue = unflipqueue;
27714  unflipqueue = swapqueue;
27715 
27716  totalsptcount = 0l;
27717  iter = 0;
27718 
27719  while ((flipqueue->objects > 0l) && (steinerleft != 0)) {
27720 
27721  sptcount = 0l;
27722 
27723  if (b->verbose > 1) {
27724  printf(" Splitting bad quality tets [%d]#: %ld.\n",
27725  iter, flipqueue->objects);
27726  }
27727 
27728  for (k = 0; (k < flipqueue->objects) && (steinerleft != 0); k++) {
27729  bface = (badface *) fastlookup(flipqueue, k);
27730  if (gettetrahedron(bface->forg, bface->fdest, bface->fapex,
27731  bface->foppo, &bface->tt)) {
27732  if ((bface->key == 0) || (bface->tt.ver != 11)) {
27733  // Here we need to re-compute the quality. Since other smoothing
27734  // operation may have moved the vertices of this tet.
27735  ppt = (point *) & (bface->tt.tet[4]);
27736  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], bface->cent,
27737  &bface->key, NULL);
27738  }
27739  if (bface->key < cosslidihed) {
27740  // It is a sliver. Try to split it.
27741  slitet.tet = bface->tt.tet;
27742  //cosdd = bface->cent;
27743  for (j = 0; j < 6; j++) {
27744  if (bface->cent[j] < cosslidihed) {
27745  // Found a large dihedral angle.
27746  slitet.ver = edge2ver[j]; // Go to the edge.
27747  if (splitsliver(&slitet, bface->cent[j], chkencflag)) {
27748  sptcount++;
27749  break;
27750  }
27751  }
27752  } // j
27753  if (j < 6) {
27754  // A sliver is split. Queue new slivers.
27755  badtetrahedrons->traversalinit();
27756  parytet = (triface *) badtetrahedrons->traverse();
27757  while (parytet != NULL) {
27758  unmarktest2(*parytet);
27759  ppt = (point *) & (parytet->tet[4]);
27760  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], cosdd,
27761  &maxcosd, NULL);
27762  if (maxcosd < cosslidihed) {
27763  // A new sliver. Queue it.
27764  unflipqueue->newindex((void **) &parybface);
27765  parybface->forg = ppt[0];
27766  parybface->fdest = ppt[1];
27767  parybface->fapex = ppt[2];
27768  parybface->foppo = ppt[3];
27769  parybface->tt.tet = parytet->tet;
27770  parybface->tt.ver = 11;
27771  parybface->key = maxcosd;
27772  for (i = 0; i < 6; i++) {
27773  parybface->cent[i] = cosdd[i];
27774  }
27775  }
27776  parytet = (triface *) badtetrahedrons->traverse();
27777  }
27778  badtetrahedrons->restart();
27779  } else {
27780  // Didn't split. Queue it again.
27781  unflipqueue->newindex((void **) &parybface);
27782  *parybface = *bface;
27783  } // if (j == 6)
27784  } // if (bface->key < cosslidihed)
27785  } // if (gettetrahedron(...))
27786  } // k
27787 
27788  flipqueue->restart();
27789 
27790  if (b->verbose > 1) {
27791  printf(" Split %ld tets.\n", sptcount);
27792  }
27793  totalsptcount += sptcount;
27794 
27795  if (sptcount == 0l) {
27796  // No point has been smoothed.
27797  break;
27798  } else {
27799  iter++;
27800  if (iter == 2) { //if (iter >= b->optpasses) {
27801  break;
27802  }
27803  }
27804 
27805  // Swap the two flip queues.
27806  swapqueue = flipqueue;
27807  flipqueue = unflipqueue;
27808  unflipqueue = swapqueue;
27809  } // while
27810 
27811  delete flipqueue;
27812 
27813  return totalsptcount;
27814 }
27815 
27817 // //
27818 // optimizemesh() Optimize mesh for specified objective functions. //
27819 // //
27821 
27822 void tetgenmesh::optimizemesh()
27823 {
27824  badface *parybface;
27825  triface checktet;
27826  point *ppt;
27827  int optpasses;
27828  optparameters opm;
27829  REAL ncosdd[6], maxdd;
27830  long totalremcount, remcount;
27831  long totalsmtcount, smtcount;
27832  long totalsptcount, sptcount;
27833  int chkencflag;
27834  int iter;
27835  int n;
27836 
27837  if (!b->quiet) {
27838  printf("Optimizing mesh...\n");
27839  }
27840 
27841  optpasses = ((1 << b->optlevel) - 1);
27842 
27843  if (b->verbose) {
27844  printf(" Optimization level = %d.\n", b->optlevel);
27845  printf(" Optimization scheme = %d.\n", b->optscheme);
27846  printf(" Number of iteration = %d.\n", optpasses);
27847  printf(" Min_Max dihed angle = %g.\n", b->optmaxdihedral);
27848  }
27849 
27850  totalsmtcount = totalsptcount = totalremcount = 0l;
27851 
27852  cosmaxdihed = cos(b->optmaxdihedral / 180.0 * PI);
27853  cossmtdihed = cos(b->optminsmtdihed / 180.0 * PI);
27854  cosslidihed = cos(b->optminslidihed / 180.0 * PI);
27855 
27856  int attrnum = numelemattrib - 1;
27857 
27858  // Put all bad tetrahedra into array.
27859  tetrahedrons->traversalinit();
27860  checktet.tet = tetrahedrontraverse();
27861  while (checktet.tet != NULL) {
27862  if (b->convex) { // -c
27863  // Skip this tet if it lies in the exterior.
27864  if (elemattribute(checktet.tet, attrnum) == -1.0) {
27865  checktet.tet = tetrahedrontraverse();
27866  continue;
27867  }
27868  }
27869  ppt = (point *) & (checktet.tet[4]);
27870  tetalldihedral(ppt[0], ppt[1], ppt[2], ppt[3], ncosdd, &maxdd, NULL);
27871  if (maxdd < cosmaxdihed) {
27872  // There are bad dihedral angles in this tet.
27873  unflipqueue->newindex((void **) &parybface);
27874  parybface->tt.tet = checktet.tet;
27875  parybface->tt.ver = 11;
27876  parybface->forg = ppt[0];
27877  parybface->fdest = ppt[1];
27878  parybface->fapex = ppt[2];
27879  parybface->foppo = ppt[3];
27880  parybface->key = maxdd;
27881  for (n = 0; n < 6; n++) {
27882  parybface->cent[n] = ncosdd[n];
27883  }
27884  }
27885  checktet.tet = tetrahedrontraverse();
27886  }
27887 
27888  totalremcount = improvequalitybyflips();
27889 
27890  if ((unflipqueue->objects > 0l) &&
27891  ((b->optscheme & 2) || (b->optscheme & 4))) {
27892  // The pool is only used by removeslivers().
27893  badtetrahedrons = new memorypool(sizeof(triface), b->tetrahedraperblock,
27894  sizeof(void *), 0);
27895 
27896  // Smoothing options.
27897  opm.min_max_dihedangle = 1;
27898  opm.numofsearchdirs = 10;
27899  // opm.searchstep = 0.001;
27900  opm.maxiter = 30; // Limit the maximum iterations.
27901  //opm.checkencflag = 4; // Queue affected tets after smoothing.
27902  chkencflag = 4; // Queue affected tets after splitting a sliver.
27903  iter = 0;
27904 
27905  while (iter < optpasses) {
27906  smtcount = sptcount = remcount = 0l;
27907  if (b->optscheme & 2) {
27908  smtcount += improvequalitybysmoothing(&opm);
27909  totalsmtcount += smtcount;
27910  if (smtcount > 0l) {
27911  remcount = improvequalitybyflips();
27912  totalremcount += remcount;
27913  }
27914  }
27915  if (unflipqueue->objects > 0l) {
27916  if (b->optscheme & 4) {
27917  sptcount += removeslivers(chkencflag);
27918  totalsptcount += sptcount;
27919  if (sptcount > 0l) {
27920  remcount = improvequalitybyflips();
27921  totalremcount += remcount;
27922  }
27923  }
27924  }
27925  if (unflipqueue->objects > 0l) {
27926  if (remcount > 0l) {
27927  iter++;
27928  } else {
27929  break;
27930  }
27931  } else {
27932  break;
27933  }
27934  } // while (iter)
27935 
27936  delete badtetrahedrons;
27937  badtetrahedrons = NULL;
27938  }
27939 
27940  if (unflipqueue->objects > 0l) {
27941  if (b->verbose > 1) {
27942  printf(" %ld bad tets remained.\n", unflipqueue->objects);
27943  }
27944  unflipqueue->restart();
27945  }
27946 
27947  if (b->verbose) {
27948  if (totalremcount > 0l) {
27949  printf(" Removed %ld edges.\n", totalremcount);
27950  }
27951  if (totalsmtcount > 0l) {
27952  printf(" Smoothed %ld points.\n", totalsmtcount);
27953  }
27954  if (totalsptcount > 0l) {
27955  printf(" Split %ld slivers.\n", totalsptcount);
27956  }
27957  }
27958 }
27959 
27963 
27967 
27969 // //
27970 // printfcomma() Print a (large) number with the 'thousands separator'. //
27971 // //
27972 // The following code was simply copied from "stackoverflow". //
27973 // //
27975 
27976 void tetgenmesh::printfcomma(unsigned long n)
27977 {
27978  unsigned long n2 = 0;
27979  int scale = 1;
27980  while (n >= 1000) {
27981  n2 = n2 + scale * (n % 1000);
27982  n /= 1000;
27983  scale *= 1000;
27984  }
27985  printf ("%ld", n);
27986  while (scale != 1) {
27987  scale /= 1000;
27988  n = n2 / scale;
27989  n2 = n2 % scale;
27990  printf (",%03ld", n);
27991  }
27992 }
27993 
27995 // //
27996 // checkmesh() Test the mesh for topological consistency. //
27997 // //
27998 // If 'topoflag' is set, only check the topological connection of the mesh, //
27999 // i.e., do not report degenerated or inverted elements. //
28000 // //
28002 
28003 int tetgenmesh::checkmesh(int topoflag)
28004 {
28005  triface tetloop, neightet, symtet;
28006  point pa, pb, pc, pd;
28007  REAL ori;
28008  int horrors, i;
28009 
28010  if (!b->quiet) {
28011  printf(" Checking consistency of mesh...\n");
28012  }
28013 
28014  horrors = 0;
28015  tetloop.ver = 0;
28016  // Run through the list of tetrahedra, checking each one.
28017  tetrahedrons->traversalinit();
28018  tetloop.tet = alltetrahedrontraverse();
28019  while (tetloop.tet != (tetrahedron *) NULL) {
28020  // Check all four faces of the tetrahedron.
28021  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
28022  pa = org(tetloop);
28023  pb = dest(tetloop);
28024  pc = apex(tetloop);
28025  pd = oppo(tetloop);
28026  if (tetloop.ver == 0) { // Only test for inversion once.
28027  if (!ishulltet(tetloop)) { // Only do test if it is not a hull tet.
28028  if (!topoflag) {
28029  ori = orient3d(pa, pb, pc, pd);
28030  if (ori >= 0.0) {
28031  printf(" !! !! %s ", ori > 0.0 ? "Inverted" : "Degenerated");
28032  printf(" (%d, %d, %d, %d) (ori = %.17g)\n", pointmark(pa),
28033  pointmark(pb), pointmark(pc), pointmark(pd), ori);
28034  horrors++;
28035  }
28036  }
28037  }
28038  if (infected(tetloop)) {
28039  // This may be a bug. Report it.
28040  printf(" !! (%d, %d, %d, %d) is infected.\n", pointmark(pa),
28041  pointmark(pb), pointmark(pc), pointmark(pd));
28042  horrors++;
28043  }
28044  if (marktested(tetloop)) {
28045  // This may be a bug. Report it.
28046  printf(" !! (%d, %d, %d, %d) is marked.\n", pointmark(pa),
28047  pointmark(pb), pointmark(pc), pointmark(pd));
28048  horrors++;
28049  }
28050  }
28051  if (tetloop.tet[tetloop.ver] == NULL) {
28052  printf(" !! !! No neighbor at face (%d, %d, %d).\n", pointmark(pa),
28053  pointmark(pb), pointmark(pc));
28054  horrors++;
28055  } else {
28056  // Find the neighboring tetrahedron on this face.
28057  fsym(tetloop, neightet);
28058  if (neightet.tet != NULL) {
28059  // Check that the tetrahedron's neighbor knows it's a neighbor.
28060  fsym(neightet, symtet);
28061  if ((tetloop.tet != symtet.tet) || (tetloop.ver != symtet.ver)) {
28062  printf(" !! !! Asymmetric tetra-tetra bond:\n");
28063  if (tetloop.tet == symtet.tet) {
28064  printf(" (Right tetrahedron, wrong orientation)\n");
28065  }
28066  printf(" First: (%d, %d, %d, %d)\n", pointmark(pa),
28067  pointmark(pb), pointmark(pc), pointmark(pd));
28068  printf(" Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
28069  pointmark(dest(neightet)), pointmark(apex(neightet)),
28070  pointmark(oppo(neightet)));
28071  horrors++;
28072  }
28073  // Check if they have the same edge (the bond() operation).
28074  if ((org(neightet) != pb) || (dest(neightet) != pa)) {
28075  printf(" !! !! Wrong edge-edge bond:\n");
28076  printf(" First: (%d, %d, %d, %d)\n", pointmark(pa),
28077  pointmark(pb), pointmark(pc), pointmark(pd));
28078  printf(" Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
28079  pointmark(dest(neightet)), pointmark(apex(neightet)),
28080  pointmark(oppo(neightet)));
28081  horrors++;
28082  }
28083  // Check if they have the same apex.
28084  if (apex(neightet) != pc) {
28085  printf(" !! !! Wrong face-face bond:\n");
28086  printf(" First: (%d, %d, %d, %d)\n", pointmark(pa),
28087  pointmark(pb), pointmark(pc), pointmark(pd));
28088  printf(" Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
28089  pointmark(dest(neightet)), pointmark(apex(neightet)),
28090  pointmark(oppo(neightet)));
28091  horrors++;
28092  }
28093  // Check if they have the same opposite.
28094  if (oppo(neightet) == pd) {
28095  printf(" !! !! Two identical tetra:\n");
28096  printf(" First: (%d, %d, %d, %d)\n", pointmark(pa),
28097  pointmark(pb), pointmark(pc), pointmark(pd));
28098  printf(" Second: (%d, %d, %d, %d)\n", pointmark(org(neightet)),
28099  pointmark(dest(neightet)), pointmark(apex(neightet)),
28100  pointmark(oppo(neightet)));
28101  horrors++;
28102  }
28103  } else {
28104  printf(" !! !! Tet-face has no neighbor (%d, %d, %d) - %d:\n",
28105  pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd));
28106  horrors++;
28107  }
28108  }
28109  if (facemarked(tetloop)) {
28110  // This may be a bug. Report it.
28111  printf(" !! tetface (%d, %d, %d) %d is marked.\n", pointmark(pa),
28112  pointmark(pb), pointmark(pc), pointmark(pd));
28113  }
28114  }
28115  // Check the six edges of this tet.
28116  for (i = 0; i < 6; i++) {
28117  tetloop.ver = edge2ver[i];
28118  if (edgemarked(tetloop)) {
28119  // This may be a bug. Report it.
28120  printf(" !! tetedge (%d, %d) %d, %d is marked.\n",
28121  pointmark(org(tetloop)), pointmark(dest(tetloop)),
28122  pointmark(apex(tetloop)), pointmark(oppo(tetloop)));
28123  }
28124  }
28125  tetloop.tet = alltetrahedrontraverse();
28126  }
28127  if (horrors == 0) {
28128  if (!b->quiet) {
28129  printf(" In my studied opinion, the mesh appears to be consistent.\n");
28130  }
28131  } else {
28132  printf(" !! !! !! !! %d %s witnessed.\n", horrors,
28133  horrors > 1 ? "abnormity" : "abnormities");
28134  }
28135 
28136  return horrors;
28137 }
28138 
28140 // //
28141 // checkshells() Test the boundary mesh for topological consistency. //
28142 // //
28144 #pragma GCC diagnostic push
28145 #pragma GCC diagnostic ignored "-Wformat"
28146 int tetgenmesh::checkshells()
28147 {
28148  triface neightet, symtet;
28149  face shloop, spinsh, nextsh;
28150  face checkseg;
28151  point pa, pb;
28152  int bakcount;
28153  int horrors, i;
28154 
28155  if (!b->quiet) {
28156  printf(" Checking consistency of the mesh boundary...\n");
28157  }
28158  horrors = 0;
28159 
28160  void **bakpathblock = subfaces->pathblock;
28161  void *bakpathitem = subfaces->pathitem;
28162  int bakpathitemsleft = subfaces->pathitemsleft;
28163  int bakalignbytes = subfaces->alignbytes;
28164 
28165  subfaces->traversalinit();
28166  shloop.sh = shellfacetraverse(subfaces);
28167  while (shloop.sh != NULL) {
28168  shloop.shver = 0;
28169  for (i = 0; i < 3; i++) {
28170  // Check the face ring at this edge.
28171  pa = sorg(shloop);
28172  pb = sdest(shloop);
28173  spinsh = shloop;
28174  spivot(spinsh, nextsh);
28175  bakcount = horrors;
28176  while ((nextsh.sh != NULL) && (nextsh.sh != shloop.sh)) {
28177  if (nextsh.sh[3] == NULL) {
28178  printf(" !! !! Wrong subface-subface connection (Dead subface).\n");
28179  printf(" First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
28180  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
28181  pointmark(sapex(spinsh)));
28182  printf(" Second: x%lx (DEAD)\n", (uintptr_t) nextsh.sh);
28183  horrors++;
28184  break;
28185  }
28186  // check if they have the same edge.
28187  if (!(((sorg(nextsh) == pa) && (sdest(nextsh) == pb)) ||
28188  ((sorg(nextsh) == pb) && (sdest(nextsh) == pa)))) {
28189  printf(" !! !! Wrong subface-subface connection.\n");
28190  printf(" First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
28191  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
28192  pointmark(sapex(spinsh)));
28193  printf(" Scond: x%lx (%d, %d, %d).\n", (uintptr_t) nextsh.sh,
28194  pointmark(sorg(nextsh)), pointmark(sdest(nextsh)),
28195  pointmark(sapex(nextsh)));
28196  horrors++;
28197  break;
28198  }
28199  // Check they should not have the same apex.
28200  if (sapex(nextsh) == sapex(spinsh)) {
28201  printf(" !! !! Existing two duplicated subfaces.\n");
28202  printf(" First: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
28203  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
28204  pointmark(sapex(spinsh)));
28205  printf(" Scond: x%lx (%d, %d, %d).\n", (uintptr_t) nextsh.sh,
28206  pointmark(sorg(nextsh)), pointmark(sdest(nextsh)),
28207  pointmark(sapex(nextsh)));
28208  horrors++;
28209  break;
28210  }
28211  spinsh = nextsh;
28212  spivot(spinsh, nextsh);
28213  }
28214  // Check subface-subseg bond.
28215  sspivot(shloop, checkseg);
28216  if (checkseg.sh != NULL) {
28217  if (checkseg.sh[3] == NULL) {
28218  printf(" !! !! Wrong subface-subseg connection (Dead subseg).\n");
28219  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
28220  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
28221  pointmark(sapex(shloop)));
28222  printf(" Sub: x%lx (Dead)\n", (uintptr_t) checkseg.sh);
28223  horrors++;
28224  } else {
28225  if (!(((sorg(checkseg) == pa) && (sdest(checkseg) == pb)) ||
28226  ((sorg(checkseg) == pb) && (sdest(checkseg) == pa)))) {
28227  printf(" !! !! Wrong subface-subseg connection.\n");
28228  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
28229  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
28230  pointmark(sapex(shloop)));
28231  printf(" Seg: x%lx (%d, %d).\n", (uintptr_t) checkseg.sh,
28232  pointmark(sorg(checkseg)), pointmark(sdest(checkseg)));
28233  horrors++;
28234  }
28235  }
28236  }
28237  if (horrors > bakcount) break; // An error detected.
28238  senextself(shloop);
28239  }
28240  // Check tet-subface connection.
28241  stpivot(shloop, neightet);
28242  if (neightet.tet != NULL) {
28243  if (neightet.tet[4] == NULL) {
28244  printf(" !! !! Wrong sub-to-tet connection (Dead tet)\n");
28245  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
28246  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
28247  pointmark(sapex(shloop)));
28248  printf(" Tet: x%lx (DEAD)\n", (uintptr_t) neightet.tet);
28249  horrors++;
28250  } else {
28251  if (!((sorg(shloop) == org(neightet)) &&
28252  (sdest(shloop) == dest(neightet)))) {
28253  printf(" !! !! Wrong sub-to-tet connection\n");
28254  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) shloop.sh,
28255  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
28256  pointmark(sapex(shloop)));
28257  printf(" Tet: x%lx (%d, %d, %d, %d).\n",
28258  (uintptr_t) neightet.tet, pointmark(org(neightet)),
28259  pointmark(dest(neightet)), pointmark(apex(neightet)),
28260  pointmark(oppo(neightet)));
28261  horrors++;
28262  }
28263  tspivot(neightet, spinsh);
28264  if (!((sorg(spinsh) == org(neightet)) &&
28265  (sdest(spinsh) == dest(neightet)))) {
28266  printf(" !! !! Wrong tet-sub connection.\n");
28267  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
28268  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
28269  pointmark(sapex(spinsh)));
28270  printf(" Tet: x%lx (%d, %d, %d, %d).\n",
28271  (uintptr_t) neightet.tet, pointmark(org(neightet)),
28272  pointmark(dest(neightet)), pointmark(apex(neightet)),
28273  pointmark(oppo(neightet)));
28274  horrors++;
28275  }
28276  fsym(neightet, symtet);
28277  tspivot(symtet, spinsh);
28278  if (spinsh.sh != NULL) {
28279  if (!((sorg(spinsh) == org(symtet)) &&
28280  (sdest(spinsh) == dest(symtet)))) {
28281  printf(" !! !! Wrong tet-sub connection.\n");
28282  printf(" Sub: x%lx (%d, %d, %d).\n", (uintptr_t) spinsh.sh,
28283  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
28284  pointmark(sapex(spinsh)));
28285  printf(" Tet: x%lx (%d, %d, %d, %d).\n",
28286  (uintptr_t) symtet.tet, pointmark(org(symtet)),
28287  pointmark(dest(symtet)), pointmark(apex(symtet)),
28288  pointmark(oppo(symtet)));
28289  horrors++;
28290  }
28291  } else {
28292  printf(" Warning: Broken tet-sub-tet connection.\n");
28293  }
28294  }
28295  }
28296  if (sinfected(shloop)) {
28297  // This may be a bug. report it.
28298  printf(" !! A infected subface: (%d, %d, %d).\n",
28299  pointmark(sorg(shloop)), pointmark(sdest(shloop)),
28300  pointmark(sapex(shloop)));
28301  }
28302  if (smarktested(shloop)) {
28303  // This may be a bug. report it.
28304  printf(" !! A marked subface: (%d, %d, %d).\n", pointmark(sorg(shloop)),
28305  pointmark(sdest(shloop)), pointmark(sapex(shloop)));
28306  }
28307  shloop.sh = shellfacetraverse(subfaces);
28308  }
28309 
28310  if (horrors == 0) {
28311  if (!b->quiet) {
28312  printf(" Mesh boundaries connected correctly.\n");
28313  }
28314  } else {
28315  printf(" !! !! !! !! %d boundary connection viewed with horror.\n",
28316  horrors);
28317  }
28318 
28319  subfaces->pathblock = bakpathblock;
28320  subfaces->pathitem = bakpathitem;
28321  subfaces->pathitemsleft = bakpathitemsleft;
28322  subfaces->alignbytes = bakalignbytes;
28323 
28324  return horrors;
28325 }
28326 
28328 // //
28329 // checksegments() Check the connections between tetrahedra and segments. //
28330 // //
28332 
28333 int tetgenmesh::checksegments()
28334 {
28335  triface tetloop, neightet, spintet;
28336  shellface *segs;
28337  face neighsh, spinsh, checksh;
28338  face sseg, checkseg;
28339  point pa, pb;
28340  int miscount;
28341  int t1ver;
28342  int horrors, i;
28343 
28344 
28345  if (!b->quiet) {
28346  printf(" Checking tet->seg connections...\n");
28347  }
28348 
28349  horrors = 0;
28350  tetrahedrons->traversalinit();
28351  tetloop.tet = tetrahedrontraverse();
28352  while (tetloop.tet != NULL) {
28353  // Loop the six edges of the tet.
28354  if (tetloop.tet[8] != NULL) {
28355  segs = (shellface *) tetloop.tet[8];
28356  for (i = 0; i < 6; i++) {
28357  sdecode(segs[i], sseg);
28358  if (sseg.sh != NULL) {
28359  // Get the edge of the tet.
28360  tetloop.ver = edge2ver[i];
28361  // Check if they are the same edge.
28362  pa = (point) sseg.sh[3];
28363  pb = (point) sseg.sh[4];
28364  if (!(((org(tetloop) == pa) && (dest(tetloop) == pb)) ||
28365  ((org(tetloop) == pb) && (dest(tetloop) == pa)))) {
28366  printf(" !! Wrong tet-seg connection.\n");
28367  printf(" Tet: x%lx (%d, %d, %d, %d) - Seg: x%lx (%d, %d).\n",
28368  (uintptr_t) tetloop.tet, pointmark(org(tetloop)),
28369  pointmark(dest(tetloop)), pointmark(apex(tetloop)),
28370  pointmark(oppo(tetloop)), (uintptr_t) sseg.sh,
28371  pointmark(pa), pointmark(pb));
28372  horrors++;
28373  } else {
28374  // Loop all tets sharing at this edge.
28375  neightet = tetloop;
28376  do {
28377  tsspivot1(neightet, checkseg);
28378  if (checkseg.sh != sseg.sh) {
28379  printf(" !! Wrong tet->seg connection.\n");
28380  printf(" Tet: x%lx (%d, %d, %d, %d) - ",
28381  (uintptr_t) neightet.tet, pointmark(org(neightet)),
28382  pointmark(dest(neightet)), pointmark(apex(neightet)),
28383  pointmark(oppo(neightet)));
28384  if (checkseg.sh != NULL) {
28385  printf("Seg x%lx (%d, %d).\n", (uintptr_t) checkseg.sh,
28386  pointmark(sorg(checkseg)),pointmark(sdest(checkseg)));
28387  } else {
28388  printf("Seg: NULL.\n");
28389  }
28390  horrors++;
28391  }
28392  fnextself(neightet);
28393  } while (neightet.tet != tetloop.tet);
28394  }
28395  // Check the seg->tet pointer.
28396  sstpivot1(sseg, neightet);
28397  if (neightet.tet == NULL) {
28398  printf(" !! Wrong seg->tet connection (A NULL tet).\n");
28399  horrors++;
28400  } else {
28401  if (!(((org(neightet) == pa) && (dest(neightet) == pb)) ||
28402  ((org(neightet) == pb) && (dest(neightet) == pa)))) {
28403  printf(" !! Wrong seg->tet connection (Wrong edge).\n");
28404  printf(" Tet: x%lx (%d, %d, %d, %d) - Seg: x%lx (%d, %d).\n",
28405  (uintptr_t) neightet.tet, pointmark(org(neightet)),
28406  pointmark(dest(neightet)), pointmark(apex(neightet)),
28407  pointmark(oppo(neightet)), (uintptr_t) sseg.sh,
28408  pointmark(pa), pointmark(pb));
28409  horrors++;
28410  }
28411  }
28412  }
28413  }
28414  }
28415  // Loop the six edge of this tet.
28416  neightet.tet = tetloop.tet;
28417  for (i = 0; i < 6; i++) {
28418  neightet.ver = edge2ver[i];
28419  if (edgemarked(neightet)) {
28420  // A possible bug. Report it.
28421  printf(" !! A marked edge: (%d, %d, %d, %d) -- x%lx %d.\n",
28422  pointmark(org(neightet)), pointmark(dest(neightet)),
28423  pointmark(apex(neightet)), pointmark(oppo(neightet)),
28424  (uintptr_t) neightet.tet, neightet.ver);
28425  // Check if all tets at the edge are marked.
28426  spintet = neightet;
28427  while (1) {
28428  fnextself(spintet);
28429  if (!edgemarked(spintet)) {
28430  printf(" !! !! An unmarked edge (%d, %d, %d, %d) -- x%lx %d.\n",
28431  pointmark(org(spintet)), pointmark(dest(spintet)),
28432  pointmark(apex(spintet)), pointmark(oppo(spintet)),
28433  (uintptr_t) spintet.tet, spintet.ver);
28434  horrors++;
28435  }
28436  if (spintet.tet == neightet.tet) break;
28437  }
28438  }
28439  }
28440  tetloop.tet = tetrahedrontraverse();
28441  }
28442 
28443  if (!b->quiet) {
28444  printf(" Checking seg->tet connections...\n");
28445  }
28446 
28447  miscount = 0; // Count the number of unrecovered segments.
28448  subsegs->traversalinit();
28449  sseg.shver = 0;
28450  sseg.sh = shellfacetraverse(subsegs);
28451  while (sseg.sh != NULL) {
28452  pa = sorg(sseg);
28453  pb = sdest(sseg);
28454  spivot(sseg, neighsh);
28455  if (neighsh.sh != NULL) {
28456  spinsh = neighsh;
28457  while (1) {
28458  // Check seg-subface bond.
28459  if (((sorg(spinsh) == pa) && (sdest(spinsh) == pb)) ||
28460  ((sorg(spinsh) == pb) && (sdest(spinsh) == pa))) {
28461  // Keep the same rotate direction.
28462  //if (sorg(spinsh) != pa) {
28463  // sesymself(spinsh);
28464  // printf(" !! Wrong ori at subface (%d, %d, %d) -- x%lx %d\n",
28465  // pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
28466  // pointmark(sapex(spinsh)), (uintptr_t) spinsh.sh,
28467  // spinsh.shver);
28468  // horrors++;
28469  //}
28470  stpivot(spinsh, spintet);
28471  if (spintet.tet != NULL) {
28472  // Check if all tets at this segment.
28473  while (1) {
28474  tsspivot1(spintet, checkseg);
28475  if (checkseg.sh == NULL) {
28476  printf(" !! !! No seg at tet (%d, %d, %d, %d) -- x%lx %d\n",
28477  pointmark(org(spintet)), pointmark(dest(spintet)),
28478  pointmark(apex(spintet)), pointmark(oppo(spintet)),
28479  (uintptr_t) spintet.tet, spintet.ver);
28480  horrors++;
28481  }
28482  if (checkseg.sh != sseg.sh) {
28483  printf(" !! !! Wrong seg (%d, %d) at tet (%d, %d, %d, %d)\n",
28484  pointmark(sorg(checkseg)), pointmark(sdest(checkseg)),
28485  pointmark(org(spintet)), pointmark(dest(spintet)),
28486  pointmark(apex(spintet)), pointmark(oppo(spintet)));
28487  horrors++;
28488  }
28489  fnextself(spintet);
28490  // Stop at the next subface.
28491  tspivot(spintet, checksh);
28492  if (checksh.sh != NULL) break;
28493  } // while (1)
28494  }
28495  } else {
28496  printf(" !! Wrong seg-subface (%d, %d, %d) -- x%lx %d connect\n",
28497  pointmark(sorg(spinsh)), pointmark(sdest(spinsh)),
28498  pointmark(sapex(spinsh)), (uintptr_t) spinsh.sh,
28499  spinsh.shver);
28500  horrors++;
28501  break;
28502  } // if pa, pb
28503  spivotself(spinsh);
28504  if (spinsh.sh == NULL) break; // A dangling segment.
28505  if (spinsh.sh == neighsh.sh) break;
28506  } // while (1)
28507  } // if (neighsh.sh != NULL)
28508  // Count the number of "un-recovered" segments.
28509  sstpivot1(sseg, neightet);
28510  if (neightet.tet == NULL) {
28511  miscount++;
28512  }
28513  sseg.sh = shellfacetraverse(subsegs);
28514  }
28515 
28516  if (!b->quiet) {
28517  printf(" Checking seg->seg connections...\n");
28518  }
28519 
28520  points->traversalinit();
28521  pa = pointtraverse();
28522  while (pa != NULL) {
28523  if (pointtype(pa) == FREESEGVERTEX) {
28524  // There should be two subsegments connected at 'pa'.
28525  // Get a subsegment containing 'pa'.
28526  sdecode(point2sh(pa), sseg);
28527  if ((sseg.sh == NULL) || sseg.sh[3] == NULL) {
28528  printf(" !! Dead point-to-seg pointer at point %d.\n",
28529  pointmark(pa));
28530  horrors++;
28531  } else {
28532  sseg.shver = 0;
28533  if (sorg(sseg) != pa) {
28534  if (sdest(sseg) != pa) {
28535  printf(" !! Wrong point-to-seg pointer at point %d.\n",
28536  pointmark(pa));
28537  horrors++;
28538  } else {
28539  // Find the next subsegment at 'pa'.
28540  senext(sseg, checkseg);
28541  if ((checkseg.sh == NULL) || (checkseg.sh[3] == NULL)) {
28542  printf(" !! Dead seg-seg connection at point %d.\n",
28543  pointmark(pa));
28544  horrors++;
28545  } else {
28546  spivotself(checkseg);
28547  checkseg.shver = 0;
28548  if ((sorg(checkseg) != pa) && (sdest(checkseg) != pa)) {
28549  printf(" !! Wrong seg-seg connection at point %d.\n",
28550  pointmark(pa));
28551  horrors++;
28552  }
28553  }
28554  }
28555  } else {
28556  // Find the previous subsegment at 'pa'.
28557  senext2(sseg, checkseg);
28558  if ((checkseg.sh == NULL) || (checkseg.sh[3] == NULL)) {
28559  printf(" !! Dead seg-seg connection at point %d.\n",
28560  pointmark(pa));
28561  horrors++;
28562  } else {
28563  spivotself(checkseg);
28564  checkseg.shver = 0;
28565  if ((sorg(checkseg) != pa) && (sdest(checkseg) != pa)) {
28566  printf(" !! Wrong seg-seg connection at point %d.\n",
28567  pointmark(pa));
28568  horrors++;
28569  }
28570  }
28571  }
28572  }
28573  }
28574  pa = pointtraverse();
28575  }
28576 
28577  if (horrors == 0) {
28578  printf(" Segments are connected properly.\n");
28579  } else {
28580  printf(" !! !! !! !! Found %d missing connections.\n", horrors);
28581  }
28582  if (miscount > 0) {
28583  printf(" !! !! Found %d missing segments.\n", miscount);
28584  }
28585 
28586  return horrors;
28587 }
28588 #pragma GCC diagnostic pop
28589 
28591 // //
28592 // checkdelaunay() Ensure that the mesh is (constrained) Delaunay. //
28593 // //
28595 
28596 int tetgenmesh::checkdelaunay(int perturb)
28597 {
28598  triface tetloop;
28599  triface symtet;
28600  face checksh;
28601  point pa, pb, pc, pd, pe;
28602  REAL sign;
28603  int ndcount; // Count the non-locally Delaunay faces.
28604  int horrors;
28605 
28606  if (!b->quiet) {
28607  printf(" Checking Delaunay property of the mesh...\n");
28608  }
28609 
28610  ndcount = 0;
28611  horrors = 0;
28612  tetloop.ver = 0;
28613  // Run through the list of triangles, checking each one.
28614  tetrahedrons->traversalinit();
28615  tetloop.tet = tetrahedrontraverse();
28616  while (tetloop.tet != (tetrahedron *) NULL) {
28617  // Check all four faces of the tetrahedron.
28618  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
28619  fsym(tetloop, symtet);
28620  // Only do test if its adjoining tet is not a hull tet or its pointer
28621  // is larger (to ensure that each pair isn't tested twice).
28622  if (((point) symtet.tet[7] != dummypoint)&&(tetloop.tet < symtet.tet)) {
28623  pa = org(tetloop);
28624  pb = dest(tetloop);
28625  pc = apex(tetloop);
28626  pd = oppo(tetloop);
28627  pe = oppo(symtet);
28628  if (perturb) {
28629  sign = insphere_s(pa, pb, pc, pd, pe);
28630  } else {
28631  sign = insphere(pa, pb, pc, pd, pe);
28632  }
28633  if (sign < 0.0) {
28634  ndcount++;
28635  if (checksubfaceflag) {
28636  tspivot(tetloop, checksh);
28637  }
28638  if (checksh.sh == NULL) {
28639  printf(" !! Non-locally Delaunay (%d, %d, %d) - %d, %d\n",
28640  pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd),
28641  pointmark(pe));
28642  horrors++;
28643  }
28644  }
28645  }
28646  }
28647  tetloop.tet = tetrahedrontraverse();
28648  }
28649 
28650  if (horrors == 0) {
28651  if (!b->quiet) {
28652  if (ndcount > 0) {
28653  printf(" The mesh is constrained Delaunay.\n");
28654  } else {
28655  printf(" The mesh is Delaunay.\n");
28656  }
28657  }
28658  } else {
28659  printf(" !! !! !! !! Found %d non-Delaunay faces.\n", horrors);
28660  }
28661 
28662  return horrors;
28663 }
28664 
28666 // //
28667 // Check if the current tetrahedralization is (constrained) regular. //
28668 // //
28669 // The parameter 'type' determines which regularity should be checked: //
28670 // - 0: check the Delaunay property. //
28671 // - 1: check the Delaunay property with symbolic perturbation. //
28672 // - 2: check the regular property, the weights are stored in p[3]. //
28673 // - 3: check the regular property with symbolic perturbation. //
28674 // //
28676 
28677 int tetgenmesh::checkregular(int type)
28678 {
28679  triface tetloop;
28680  triface symtet;
28681  face checksh;
28682  point p[5];
28683  REAL sign;
28684  int ndcount; // Count the non-locally Delaunay faces.
28685  int horrors;
28686 
28687  if (!b->quiet) {
28688  printf(" Checking %s %s property of the mesh...\n",
28689  (type & 2) == 0 ? "Delaunay" : "regular",
28690  (type & 1) == 0 ? " " : "(s)");
28691  }
28692 
28693  // Make sure orient3d(p[1], p[0], p[2], p[3]) > 0;
28694  // Hence if (insphere(p[1], p[0], p[2], p[3], p[4]) > 0) means that
28695  // p[4] lies inside the circumsphere of p[1], p[0], p[2], p[3].
28696  // The same if orient4d(p[1], p[0], p[2], p[3], p[4]) > 0 means that
28697  // p[4] lies below the oriented hyperplane passing through
28698  // p[1], p[0], p[2], p[3].
28699 
28700  ndcount = 0;
28701  horrors = 0;
28702  tetloop.ver = 0;
28703  // Run through the list of triangles, checking each one.
28704  tetrahedrons->traversalinit();
28705  tetloop.tet = tetrahedrontraverse();
28706  while (tetloop.tet != (tetrahedron *) NULL) {
28707  // Check all four faces of the tetrahedron.
28708  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
28709  fsym(tetloop, symtet);
28710  // Only do test if its adjoining tet is not a hull tet or its pointer
28711  // is larger (to ensure that each pair isn't tested twice).
28712  if (((point) symtet.tet[7] != dummypoint)&&(tetloop.tet < symtet.tet)) {
28713  p[0] = org(tetloop); // pa
28714  p[1] = dest(tetloop); // pb
28715  p[2] = apex(tetloop); // pc
28716  p[3] = oppo(tetloop); // pd
28717  p[4] = oppo(symtet); // pe
28718 
28719  if (type == 0) {
28720  sign = insphere(p[1], p[0], p[2], p[3], p[4]);
28721  } else if (type == 1) {
28722  sign = insphere_s(p[1], p[0], p[2], p[3], p[4]);
28723  } else if (type == 2) {
28724  sign = orient4d(p[1], p[0], p[2], p[3], p[4],
28725  p[1][3], p[0][3], p[2][3], p[3][3], p[4][3]);
28726  } else { // type == 3
28727  sign = orient4d_s(p[1], p[0], p[2], p[3], p[4],
28728  p[1][3], p[0][3], p[2][3], p[3][3], p[4][3]);
28729  }
28730 
28731  if (sign > 0.0) {
28732  ndcount++;
28733  if (checksubfaceflag) {
28734  tspivot(tetloop, checksh);
28735  }
28736  if (checksh.sh == NULL) {
28737  printf(" !! Non-locally %s (%d, %d, %d) - %d, %d\n",
28738  (type & 2) == 0 ? "Delaunay" : "regular",
28739  pointmark(p[0]), pointmark(p[1]), pointmark(p[2]),
28740  pointmark(p[3]), pointmark(p[4]));
28741  horrors++;
28742  }
28743  }
28744  }
28745  }
28746  tetloop.tet = tetrahedrontraverse();
28747  }
28748 
28749  if (horrors == 0) {
28750  if (!b->quiet) {
28751  if (ndcount > 0) {
28752  printf(" The mesh is constrained %s.\n",
28753  (type & 2) == 0 ? "Delaunay" : "regular");
28754  } else {
28755  printf(" The mesh is %s.\n", (type & 2) == 0 ? "Delaunay" : "regular");
28756  }
28757  }
28758  } else {
28759  printf(" !! !! !! !! Found %d non-%s faces.\n", horrors,
28760  (type & 2) == 0 ? "Delaunay" : "regular");
28761  }
28762 
28763  return horrors;
28764 }
28765 
28767 // //
28768 // checkconforming() Ensure that the mesh is conforming Delaunay. //
28769 // //
28770 // If 'flag' is 1, only check subsegments. If 'flag' is 2, check subfaces. //
28771 // If 'flag' is 3, check both subsegments and subfaces. //
28772 // //
28774 
28775 int tetgenmesh::checkconforming(int flag)
28776 {
28777  triface searchtet, neightet, spintet;
28778  face shloop;
28779  face segloop;
28780  point eorg, edest, eapex, pa, pb, pc;
28781  REAL cent[3], radius, dist, diff, rd, len;
28782  bool enq;
28783  int encsubsegs, encsubfaces;
28784  int t1ver;
28785  int i;
28786 
28787  REAL A[4][4], rhs[4], D;
28788  int indx[4];
28789  REAL elen[3];
28790 
28791  encsubsegs = 0;
28792 
28793  if (flag & 1) {
28794  if (!b->quiet) {
28795  printf(" Checking conforming property of segments...\n");
28796  }
28797  encsubsegs = 0;
28798 
28799  // Run through the list of subsegments, check each one.
28800  subsegs->traversalinit();
28801  segloop.sh = shellfacetraverse(subsegs);
28802  while (segloop.sh != (shellface *) NULL) {
28803  eorg = (point) segloop.sh[3];
28804  edest = (point) segloop.sh[4];
28805  radius = 0.5 * distance(eorg, edest);
28806  for (i = 0; i < 3; i++) cent[i] = 0.5 * (eorg[i] + edest[i]);
28807 
28808  enq = false;
28809  sstpivot1(segloop, neightet);
28810  if (neightet.tet != NULL) {
28811  spintet = neightet;
28812  while (1) {
28813  eapex= apex(spintet);
28814  if (eapex != dummypoint) {
28815  dist = distance(eapex, cent);
28816  diff = dist - radius;
28817  if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding.
28818  if (diff < 0) {
28819  enq = true; break;
28820  }
28821  }
28822  fnextself(spintet);
28823  if (spintet.tet == neightet.tet) break;
28824  }
28825  }
28826  if (enq) {
28827  printf(" !! !! Non-conforming segment: (%d, %d)\n",
28828  pointmark(eorg), pointmark(edest));
28829  encsubsegs++;
28830  }
28831  segloop.sh = shellfacetraverse(subsegs);
28832  }
28833 
28834  if (encsubsegs == 0) {
28835  if (!b->quiet) {
28836  printf(" The segments are conforming Delaunay.\n");
28837  }
28838  } else {
28839  printf(" !! !! %d subsegments are non-conforming.\n", encsubsegs);
28840  }
28841  } // if (flag & 1)
28842 
28843  encsubfaces = 0;
28844 
28845  if (flag & 2) {
28846  if (!b->quiet) {
28847  printf(" Checking conforming property of subfaces...\n");
28848  }
28849 
28850  // Run through the list of subfaces, check each one.
28851  subfaces->traversalinit();
28852  shloop.sh = shellfacetraverse(subfaces);
28853  while (shloop.sh != (shellface *) NULL) {
28854  pa = (point) shloop.sh[3];
28855  pb = (point) shloop.sh[4];
28856  pc = (point) shloop.sh[5];
28857 
28858  // Compute the coefficient matrix A (3x3).
28859  A[0][0] = pb[0] - pa[0];
28860  A[0][1] = pb[1] - pa[1];
28861  A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb)
28862  A[1][0] = pc[0] - pa[0];
28863  A[1][1] = pc[1] - pa[1];
28864  A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc)
28865  cross(A[0], A[1], A[2]); // vector V3 (V1 X V2)
28866 
28867  // Compute the right hand side vector b (3x1).
28868  elen[0] = dot(A[0], A[0]);
28869  elen[1] = dot(A[1], A[1]);
28870  rhs[0] = 0.5 * elen[0];
28871  rhs[1] = 0.5 * elen[1];
28872  rhs[2] = 0.0;
28873 
28874  if (lu_decmp(A, 3, indx, &D, 0)) {
28875  lu_solve(A, 3, indx, rhs, 0);
28876  cent[0] = pa[0] + rhs[0];
28877  cent[1] = pa[1] + rhs[1];
28878  cent[2] = pa[2] + rhs[2];
28879  rd = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]);
28880 
28881  // Check if this subface is encroached.
28882  for (i = 0; i < 2; i++) {
28883  stpivot(shloop, searchtet);
28884  if (!ishulltet(searchtet)) {
28885  len = distance(oppo(searchtet), cent);
28886  if ((fabs(len - rd) / rd) < b->epsilon) len = rd; // Rounding.
28887  if (len < rd) {
28888  printf(" !! !! Non-conforming subface: (%d, %d, %d)\n",
28889  pointmark(pa), pointmark(pb), pointmark(pc));
28890  encsubfaces++;
28891  enq = true; break;
28892  }
28893  }
28894  sesymself(shloop);
28895  }
28896  }
28897  shloop.sh = shellfacetraverse(subfaces);
28898  }
28899 
28900  if (encsubfaces == 0) {
28901  if (!b->quiet) {
28902  printf(" The subfaces are conforming Delaunay.\n");
28903  }
28904  } else {
28905  printf(" !! !! %d subfaces are non-conforming.\n", encsubfaces);
28906  }
28907  } // if (flag & 2)
28908 
28909  return encsubsegs + encsubfaces;
28910 }
28911 
28913 // //
28914 // qualitystatistics() Print statistics about the quality of the mesh. //
28915 // //
28917 
28918 void tetgenmesh::qualitystatistics()
28919 {
28920  triface tetloop, neightet;
28921  point p[4];
28922  char sbuf[128];
28923  REAL radiusratiotable[12];
28924  REAL aspectratiotable[12];
28925  REAL A[4][4], rhs[4], D;
28926  REAL V[6][3], N[4][3], H[4]; // edge-vectors, face-normals, face-heights.
28927  REAL edgelength[6], alldihed[6], faceangle[3];
28928  REAL shortest, longest;
28929  REAL smallestvolume, biggestvolume;
28930  REAL smallestratio, biggestratio;
28931  REAL smallestradiusratio, biggestradiusratio; // radius-edge ratio.
28932  REAL smallestdiangle, biggestdiangle;
28933  REAL smallestfaangle, biggestfaangle;
28934  REAL total_tet_vol, total_tetprism_vol;
28935  REAL tetvol, minaltitude;
28936  REAL cirradius, minheightinv; // insradius;
28937  REAL shortlen, longlen;
28938  REAL tetaspect, tetradius;
28939  REAL smalldiangle, bigdiangle;
28940  REAL smallfaangle, bigfaangle;
28941  unsigned long radiustable[12];
28942  unsigned long aspecttable[16];
28943  unsigned long dihedangletable[18];
28944  unsigned long faceangletable[18];
28945  int indx[4];
28946  int radiusindex;
28947  int aspectindex;
28948  int tendegree;
28949  int i, j;
28950  // Report the tet which has the biggest radius-edge ratio.
28951  triface biggestradiusratiotet;
28952 
28953  printf("Mesh quality statistics:\n\n");
28954 
28955  shortlen = longlen = 0.0;
28956  smalldiangle = bigdiangle = 0.0;
28957  total_tet_vol = 0.0;
28958  total_tetprism_vol = 0.0;
28959 
28960  radiusratiotable[0] = 0.707; radiusratiotable[1] = 1.0;
28961  radiusratiotable[2] = 1.1; radiusratiotable[3] = 1.2;
28962  radiusratiotable[4] = 1.4; radiusratiotable[5] = 1.6;
28963  radiusratiotable[6] = 1.8; radiusratiotable[7] = 2.0;
28964  radiusratiotable[8] = 2.5; radiusratiotable[9] = 3.0;
28965  radiusratiotable[10] = 10.0; radiusratiotable[11] = 0.0;
28966 
28967  aspectratiotable[0] = 1.5; aspectratiotable[1] = 2.0;
28968  aspectratiotable[2] = 2.5; aspectratiotable[3] = 3.0;
28969  aspectratiotable[4] = 4.0; aspectratiotable[5] = 6.0;
28970  aspectratiotable[6] = 10.0; aspectratiotable[7] = 15.0;
28971  aspectratiotable[8] = 25.0; aspectratiotable[9] = 50.0;
28972  aspectratiotable[10] = 100.0; aspectratiotable[11] = 0.0;
28973 
28974  for (i = 0; i < 12; i++) radiustable[i] = 0l;
28975  for (i = 0; i < 12; i++) aspecttable[i] = 0l;
28976  for (i = 0; i < 18; i++) dihedangletable[i] = 0l;
28977  for (i = 0; i < 18; i++) faceangletable[i] = 0l;
28978 
28979  minaltitude = xmax - xmin + ymax - ymin + zmax - zmin;
28980  minaltitude = minaltitude * minaltitude;
28981  shortest = minaltitude;
28982  longest = 0.0;
28983  smallestvolume = minaltitude;
28984  biggestvolume = 0.0;
28985  smallestratio = smallestradiusratio = 1e+16; // minaltitude;
28986  biggestratio = biggestradiusratio = 0.0;
28987  smallestdiangle = smallestfaangle = 180.0;
28988  biggestdiangle = biggestfaangle = 0.0;
28989 
28990 
28991  int attrnum = numelemattrib - 1;
28992 
28993  // Loop all elements, calculate quality parameters for each element.
28994  tetrahedrons->traversalinit();
28995  tetloop.tet = tetrahedrontraverse();
28996  while (tetloop.tet != (tetrahedron *) NULL) {
28997 
28998  if (b->convex) {
28999  // Skip tets in the exterior.
29000  if (elemattribute(tetloop.tet, attrnum) == -1.0) {
29001  tetloop.tet = tetrahedrontraverse();
29002  continue;
29003  }
29004  }
29005 
29006  // Get four vertices: p0, p1, p2, p3.
29007  for (i = 0; i < 4; i++) p[i] = (point) tetloop.tet[4 + i];
29008 
29009  // Get the tet volume.
29010  tetvol = orient3dfast(p[1], p[0], p[2], p[3]) / 6.0;
29011  total_tet_vol += tetvol;
29012  total_tetprism_vol += tetprismvol(p[0], p[1], p[2], p[3]);
29013 
29014  // Calculate the largest and smallest volume.
29015  if (tetvol < smallestvolume) {
29016  smallestvolume = tetvol;
29017  }
29018  if (tetvol > biggestvolume) {
29019  biggestvolume = tetvol;
29020  }
29021 
29022  // Set the edge vectors: V[0], ..., V[5]
29023  for (i = 0; i < 3; i++) V[0][i] = p[0][i] - p[3][i]; // V[0]: p3->p0.
29024  for (i = 0; i < 3; i++) V[1][i] = p[1][i] - p[3][i]; // V[1]: p3->p1.
29025  for (i = 0; i < 3; i++) V[2][i] = p[2][i] - p[3][i]; // V[2]: p3->p2.
29026  for (i = 0; i < 3; i++) V[3][i] = p[1][i] - p[0][i]; // V[3]: p0->p1.
29027  for (i = 0; i < 3; i++) V[4][i] = p[2][i] - p[1][i]; // V[4]: p1->p2.
29028  for (i = 0; i < 3; i++) V[5][i] = p[0][i] - p[2][i]; // V[5]: p2->p0.
29029 
29030  // Get the squares of the edge lengths.
29031  for (i = 0; i < 6; i++) edgelength[i] = dot(V[i], V[i]);
29032 
29033  // Calculate the longest and shortest edge length.
29034  for (i = 0; i < 6; i++) {
29035  if (i == 0) {
29036  shortlen = longlen = edgelength[i];
29037  } else {
29038  shortlen = edgelength[i] < shortlen ? edgelength[i] : shortlen;
29039  longlen = edgelength[i] > longlen ? edgelength[i] : longlen;
29040  }
29041  if (edgelength[i] > longest) {
29042  longest = edgelength[i];
29043  }
29044  if (edgelength[i] < shortest) {
29045  shortest = edgelength[i];
29046  }
29047  }
29048 
29049  // Set the matrix A = [V[0], V[1], V[2]]^T.
29050  for (j = 0; j < 3; j++) {
29051  for (i = 0; i < 3; i++) A[j][i] = V[j][i];
29052  }
29053 
29054  // Decompose A just once.
29055  if (lu_decmp(A, 3, indx, &D, 0)) {
29056  // Get the three faces normals.
29057  for (j = 0; j < 3; j++) {
29058  for (i = 0; i < 3; i++) rhs[i] = 0.0;
29059  rhs[j] = 1.0; // Positive means the inside direction
29060  lu_solve(A, 3, indx, rhs, 0);
29061  for (i = 0; i < 3; i++) N[j][i] = rhs[i];
29062  }
29063  // Get the fourth face normal by summing up the first three.
29064  for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i];
29065  // Get the radius of the circumsphere.
29066  for (i = 0; i < 3; i++) rhs[i] = 0.5 * dot(V[i], V[i]);
29067  lu_solve(A, 3, indx, rhs, 0);
29068  cirradius = sqrt(dot(rhs, rhs));
29069  // Normalize the face normals.
29070  for (i = 0; i < 4; i++) {
29071  // H[i] is the inverse of height of its corresponding face.
29072  H[i] = sqrt(dot(N[i], N[i]));
29073  for (j = 0; j < 3; j++) N[i][j] /= H[i];
29074  }
29075  // Get the radius of the inscribed sphere.
29076  // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]);
29077  // Get the biggest H[i] (corresponding to the smallest height).
29078  minheightinv = H[0];
29079  for (i = 1; i < 4; i++) {
29080  if (H[i] > minheightinv) minheightinv = H[i];
29081  }
29082  } else {
29083  // A nearly degenerated tet.
29084  if (tetvol <= 0.0) {
29085  printf(" !! Warning: A %s tet (%d,%d,%d,%d).\n",
29086  tetvol < 0 ? "inverted" : "degenerated", pointmark(p[0]),
29087  pointmark(p[1]), pointmark(p[2]), pointmark(p[3]));
29088  // Skip it.
29089  tetloop.tet = tetrahedrontraverse();
29090  continue;
29091  }
29092  // Calculate the four face normals.
29093  facenormal(p[2], p[1], p[3], N[0], 1, NULL);
29094  facenormal(p[0], p[2], p[3], N[1], 1, NULL);
29095  facenormal(p[1], p[0], p[3], N[2], 1, NULL);
29096  facenormal(p[0], p[1], p[2], N[3], 1, NULL);
29097  // Normalize the face normals.
29098  for (i = 0; i < 4; i++) {
29099  // H[i] is the twice of the area of the face.
29100  H[i] = sqrt(dot(N[i], N[i]));
29101  for (j = 0; j < 3; j++) N[i][j] /= H[i];
29102  }
29103  // Get the biggest H[i] / tetvol (corresponding to the smallest height).
29104  minheightinv = (H[0] / tetvol);
29105  for (i = 1; i < 4; i++) {
29106  if ((H[i] / tetvol) > minheightinv) minheightinv = (H[i] / tetvol);
29107  }
29108  // Let the circumradius to be the half of its longest edge length.
29109  cirradius = 0.5 * sqrt(longlen);
29110  }
29111 
29112  // Get the dihedrals (in degree) at each edges.
29113  j = 0;
29114  for (i = 1; i < 4; i++) {
29115  alldihed[j] = -dot(N[0], N[i]); // Edge cd, bd, bc.
29116  if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
29117  else if (alldihed[j] > 1.0) alldihed[j] = 1;
29118  alldihed[j] = acos(alldihed[j]) / PI * 180.0;
29119  j++;
29120  }
29121  for (i = 2; i < 4; i++) {
29122  alldihed[j] = -dot(N[1], N[i]); // Edge ad, ac.
29123  if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
29124  else if (alldihed[j] > 1.0) alldihed[j] = 1;
29125  alldihed[j] = acos(alldihed[j]) / PI * 180.0;
29126  j++;
29127  }
29128  alldihed[j] = -dot(N[2], N[3]); // Edge ab.
29129  if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding.
29130  else if (alldihed[j] > 1.0) alldihed[j] = 1;
29131  alldihed[j] = acos(alldihed[j]) / PI * 180.0;
29132 
29133  // Calculate the largest and smallest dihedral angles.
29134  for (i = 0; i < 6; i++) {
29135  if (i == 0) {
29136  smalldiangle = bigdiangle = alldihed[i];
29137  } else {
29138  smalldiangle = alldihed[i] < smalldiangle ? alldihed[i] : smalldiangle;
29139  bigdiangle = alldihed[i] > bigdiangle ? alldihed[i] : bigdiangle;
29140  }
29141  if (alldihed[i] < smallestdiangle) {
29142  smallestdiangle = alldihed[i];
29143  }
29144  if (alldihed[i] > biggestdiangle) {
29145  biggestdiangle = alldihed[i];
29146  }
29147  // Accumulate the corresponding number in the dihedral angle histogram.
29148  if (alldihed[i] < 5.0) {
29149  tendegree = 0;
29150  } else if (alldihed[i] >= 5.0 && alldihed[i] < 10.0) {
29151  tendegree = 1;
29152  } else if (alldihed[i] >= 80.0 && alldihed[i] < 110.0) {
29153  tendegree = 9; // Angles between 80 to 110 degree are in one entry.
29154  } else if (alldihed[i] >= 170.0 && alldihed[i] < 175.0) {
29155  tendegree = 16;
29156  } else if (alldihed[i] >= 175.0) {
29157  tendegree = 17;
29158  } else {
29159  tendegree = (int) (alldihed[i] / 10.);
29160  if (alldihed[i] < 80.0) {
29161  tendegree++; // In the left column.
29162  } else {
29163  tendegree--; // In the right column.
29164  }
29165  }
29166  dihedangletable[tendegree]++;
29167  }
29168 
29169 
29170 
29171  // Calculate the largest and smallest face angles.
29172  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
29173  fsym(tetloop, neightet);
29174  // Only do the calulation once for a face.
29175  if (((point) neightet.tet[7] == dummypoint) ||
29176  (tetloop.tet < neightet.tet)) {
29177  p[0] = org(tetloop);
29178  p[1] = dest(tetloop);
29179  p[2] = apex(tetloop);
29180  faceangle[0] = interiorangle(p[0], p[1], p[2], NULL);
29181  faceangle[1] = interiorangle(p[1], p[2], p[0], NULL);
29182  faceangle[2] = PI - (faceangle[0] + faceangle[1]);
29183  // Translate angles into degrees.
29184  for (i = 0; i < 3; i++) {
29185  faceangle[i] = (faceangle[i] * 180.0) / PI;
29186  }
29187  // Calculate the largest and smallest face angles.
29188  for (i = 0; i < 3; i++) {
29189  if (i == 0) {
29190  smallfaangle = bigfaangle = faceangle[i];
29191  } else {
29192  smallfaangle = faceangle[i] < smallfaangle ?
29193  faceangle[i] : smallfaangle;
29194  bigfaangle = faceangle[i] > bigfaangle ? faceangle[i] : bigfaangle;
29195  }
29196  if (faceangle[i] < smallestfaangle) {
29197  smallestfaangle = faceangle[i];
29198  }
29199  if (faceangle[i] > biggestfaangle) {
29200  biggestfaangle = faceangle[i];
29201  }
29202  tendegree = (int) (faceangle[i] / 10.);
29203  faceangletable[tendegree]++;
29204  }
29205  }
29206  }
29207 
29208  // Calculate aspect ratio and radius-edge ratio for this element.
29209  tetradius = cirradius / sqrt(shortlen);
29210  if (tetradius < smallestradiusratio) {
29211  smallestradiusratio = tetradius;
29212  }
29213  if (tetradius > biggestradiusratio) {
29214  biggestradiusratio = tetradius;
29215  biggestradiusratiotet.tet = tetloop.tet;
29216  }
29217  // tetaspect = sqrt(longlen) / (2.0 * insradius);
29218  tetaspect = sqrt(longlen) * minheightinv;
29219  // Remember the largest and smallest aspect ratio.
29220  if (tetaspect < smallestratio) {
29221  smallestratio = tetaspect;
29222  }
29223  if (tetaspect > biggestratio) {
29224  biggestratio = tetaspect;
29225  }
29226  // Accumulate the corresponding number in the aspect ratio histogram.
29227  aspectindex = 0;
29228  while ((tetaspect > aspectratiotable[aspectindex]) && (aspectindex < 11)) {
29229  aspectindex++;
29230  }
29231  aspecttable[aspectindex]++;
29232  radiusindex = 0;
29233  while ((tetradius > radiusratiotable[radiusindex]) && (radiusindex < 11)) {
29234  radiusindex++;
29235  }
29236  radiustable[radiusindex]++;
29237 
29238  tetloop.tet = tetrahedrontraverse();
29239  }
29240 
29241  shortest = sqrt(shortest);
29242  longest = sqrt(longest);
29243  minaltitude = sqrt(minaltitude);
29244 
29245  printf(" Smallest volume: %16.5g | Largest volume: %16.5g\n",
29246  smallestvolume, biggestvolume);
29247  printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n",
29248  shortest, longest);
29249  printf(" Smallest asp.ratio: %13.5g | Largest asp.ratio: %13.5g\n",
29250  smallestratio, biggestratio);
29251  sprintf(sbuf, "%.17g", biggestfaangle);
29252  if (strlen(sbuf) > 8) {
29253  sbuf[8] = '\0';
29254  }
29255  printf(" Smallest facangle: %14.5g | Largest facangle: %s\n",
29256  smallestfaangle, sbuf);
29257  sprintf(sbuf, "%.17g", biggestdiangle);
29258  if (strlen(sbuf) > 8) {
29259  sbuf[8] = '\0';
29260  }
29261  printf(" Smallest dihedral: %14.5g | Largest dihedral: %s\n\n",
29262  smallestdiangle, sbuf);
29263 
29264  printf(" Aspect ratio histogram:\n");
29265  printf(" < %-6.6g : %8ld | %6.6g - %-6.6g : %8ld\n",
29266  aspectratiotable[0], aspecttable[0], aspectratiotable[5],
29267  aspectratiotable[6], aspecttable[6]);
29268  for (i = 1; i < 5; i++) {
29269  printf(" %6.6g - %-6.6g : %8ld | %6.6g - %-6.6g : %8ld\n",
29270  aspectratiotable[i - 1], aspectratiotable[i], aspecttable[i],
29271  aspectratiotable[i + 5], aspectratiotable[i + 6],
29272  aspecttable[i + 6]);
29273  }
29274  printf(" %6.6g - %-6.6g : %8ld | %6.6g - : %8ld\n",
29275  aspectratiotable[4], aspectratiotable[5], aspecttable[5],
29276  aspectratiotable[10], aspecttable[11]);
29277  printf(" (A tetrahedron's aspect ratio is its longest edge length");
29278  printf(" divided by its\n");
29279  printf(" smallest side height)\n\n");
29280 
29281  printf(" Face angle histogram:\n");
29282  for (i = 0; i < 9; i++) {
29283  printf(" %3d - %3d degrees: %8ld | %3d - %3d degrees: %8ld\n",
29284  i * 10, i * 10 + 10, faceangletable[i],
29285  i * 10 + 90, i * 10 + 100, faceangletable[i + 9]);
29286  }
29287  if (minfaceang != PI) {
29288  printf(" Minimum input face angle is %g (degree).\n",
29289  minfaceang / PI * 180.0);
29290  }
29291  printf("\n");
29292 
29293  printf(" Dihedral angle histogram:\n");
29294  // Print the three two rows:
29295  printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
29296  0, 5, dihedangletable[0], 80, 110, dihedangletable[9]);
29297  printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
29298  5, 10, dihedangletable[1], 110, 120, dihedangletable[10]);
29299  // Print the third to seventh rows.
29300  for (i = 2; i < 7; i++) {
29301  printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
29302  (i - 1) * 10, (i - 1) * 10 + 10, dihedangletable[i],
29303  (i - 1) * 10 + 110, (i - 1) * 10 + 120, dihedangletable[i + 9]);
29304  }
29305  // Print the last two rows.
29306  printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
29307  60, 70, dihedangletable[7], 170, 175, dihedangletable[16]);
29308  printf(" %3d - %2d degrees: %8ld | %3d - %3d degrees: %8ld\n",
29309  70, 80, dihedangletable[8], 175, 180, dihedangletable[17]);
29310  if (minfacetdihed != PI) {
29311  printf(" Minimum input dihedral angle is %g (degree).\n",
29312  minfacetdihed / PI * 180.0);
29313  }
29314  printf("\n");
29315 
29316  printf("\n");
29317 }
29318 
29319 
29321 // //
29322 // memorystatistics() Report the memory usage. //
29323 // //
29325 
29326 void tetgenmesh::memorystatistics()
29327 {
29328  printf("Memory usage statistics:\n\n");
29329 
29330  // Count the number of blocks of tetrahedra.
29331  int tetblocks = 0;
29332  tetrahedrons->pathblock = tetrahedrons->firstblock;
29333  while (tetrahedrons->pathblock != NULL) {
29334  tetblocks++;
29335  tetrahedrons->pathblock = (void **) *(tetrahedrons->pathblock);
29336  }
29337 
29338  // Calculate the total memory (in bytes) used by storing meshes.
29339  unsigned long totalmeshmemory = 0l, totalt2shmemory = 0l;
29340  totalmeshmemory = points->maxitems * points->itembytes +
29341  tetrahedrons->maxitems * tetrahedrons->itembytes;
29342  if (b->plc || b->refine) {
29343  totalmeshmemory += (subfaces->maxitems * subfaces->itembytes +
29344  subsegs->maxitems * subsegs->itembytes);
29345  totalt2shmemory = (tet2subpool->maxitems * tet2subpool->itembytes +
29346  tet2segpool->maxitems * tet2segpool->itembytes);
29347  }
29348 
29349  unsigned long totalalgomemory = 0l;
29350  totalalgomemory = cavetetlist->totalmemory + cavebdrylist->totalmemory +
29351  caveoldtetlist->totalmemory +
29352  flippool->maxitems * flippool->itembytes;
29353  if (b->plc || b->refine) {
29354  totalalgomemory += (subsegstack->totalmemory + subfacstack->totalmemory +
29355  subvertstack->totalmemory +
29356  caveshlist->totalmemory + caveshbdlist->totalmemory +
29357  cavesegshlist->totalmemory +
29358  cavetetshlist->totalmemory +
29359  cavetetseglist->totalmemory +
29360  caveencshlist->totalmemory +
29361  caveencseglist->totalmemory +
29362  cavetetvertlist->totalmemory +
29363  unflipqueue->totalmemory);
29364  }
29365 
29366  printf(" Maximum number of tetrahedra: %ld\n", tetrahedrons->maxitems);
29367  printf(" Maximum number of tet blocks (blocksize = %d): %d\n",
29368  b->tetrahedraperblock, tetblocks);
29369  /*
29370  if (b->plc || b->refine) {
29371  printf(" Approximate memory for tetrahedral mesh (bytes): %ld\n",
29372  totalmeshmemory);
29373 
29374  printf(" Approximate memory for extra pointers (bytes): %ld\n",
29375  totalt2shmemory);
29376  } else {
29377  printf(" Approximate memory for tetrahedralization (bytes): %ld\n",
29378  totalmeshmemory);
29379  }
29380  printf(" Approximate memory for algorithms (bytes): %ld\n",
29381  totalalgomemory);
29382  printf(" Approximate memory for working arrays (bytes): %ld\n",
29383  totalworkmemory);
29384  printf(" Approximate total used memory (bytes): %ld\n",
29385  totalmeshmemory + totalt2shmemory + totalalgomemory +
29386  totalworkmemory);
29387  */
29388  if (b->plc || b->refine) {
29389  printf(" Approximate memory for tetrahedral mesh (bytes): ");
29390  printfcomma(totalmeshmemory); printf("\n");
29391 
29392  printf(" Approximate memory for extra pointers (bytes): ");
29393  printfcomma(totalt2shmemory); printf("\n");
29394  } else {
29395  printf(" Approximate memory for tetrahedralization (bytes): ");
29396  printfcomma(totalmeshmemory); printf("\n");
29397  }
29398  printf(" Approximate memory for algorithms (bytes): ");
29399  printfcomma(totalalgomemory); printf("\n");
29400  printf(" Approximate memory for working arrays (bytes): ");
29401  printfcomma(totalworkmemory); printf("\n");
29402  printf(" Approximate total used memory (bytes): ");
29403  printfcomma(totalmeshmemory + totalt2shmemory + totalalgomemory +
29404  totalworkmemory);
29405  printf("\n");
29406 
29407  printf("\n");
29408 }
29409 
29411 // //
29412 // statistics() Print all sorts of cool facts. //
29413 // //
29415 
29416 void tetgenmesh::statistics()
29417 {
29418  long tetnumber, facenumber;
29419 
29420  printf("\nStatistics:\n\n");
29421  printf(" Input points: %d\n", in->numberofpoints);
29422  if (b->refine) {
29423  printf(" Input tetrahedra: %d\n", in->numberoftetrahedra);
29424  if (in->numberoftrifaces > 0) {
29425  printf(" Input triangles: %d\n", in->numberoftrifaces);
29426  }
29427  if (in->numberofedges > 0) {
29428  printf(" Input edges: %d\n", in->numberofedges);
29429  }
29430  } else if (b->plc) {
29431  printf(" Input facets: %d\n", in->numberoffacets);
29432  printf(" Input segments: %ld\n", insegments);
29433  if (in->numberofedges > 0) {
29434  printf(" Input edges: %d\n", in->numberofedges);
29435  }
29436  printf(" Input holes: %d\n", in->numberofholes);
29437  printf(" Input regions: %d\n", in->numberofregions);
29438  }
29439 
29440  tetnumber = tetrahedrons->items - hullsize;
29441  facenumber = (tetnumber * 4l + hullsize) / 2l;
29442 
29443  if (b->weighted) { // -w option
29444  printf("\n Mesh points: %ld\n", points->items - nonregularcount);
29445  } else {
29446  printf("\n Mesh points: %ld\n", points->items);
29447  }
29448  printf(" Mesh tetrahedra: %ld\n", tetnumber);
29449  printf(" Mesh faces: %ld\n", facenumber);
29450  if (meshedges > 0l) {
29451  printf(" Mesh edges: %ld\n", meshedges);
29452  } else {
29453  if (!nonconvex) {
29454  long vsize = points->items - dupverts - unuverts;
29455  if (b->weighted) vsize -= nonregularcount;
29456  meshedges = vsize + facenumber - tetnumber - 1;
29457  printf(" Mesh edges: %ld\n", meshedges);
29458  }
29459  }
29460 
29461  if (b->plc || b->refine) {
29462  printf(" Mesh faces on exterior boundary: %ld\n", hullsize);
29463  if (meshhulledges > 0l) {
29464  printf(" Mesh edges on exterior boundary: %ld\n", meshhulledges);
29465  }
29466  printf(" Mesh faces on input facets: %ld\n", subfaces->items);
29467  printf(" Mesh edges on input segments: %ld\n", subsegs->items);
29468  if (st_facref_count > 0l) {
29469  printf(" Steiner points on input facets: %ld\n", st_facref_count);
29470  }
29471  if (st_segref_count > 0l) {
29472  printf(" Steiner points on input segments: %ld\n", st_segref_count);
29473  }
29474  if (st_volref_count > 0l) {
29475  printf(" Steiner points inside domain: %ld\n", st_volref_count);
29476  }
29477  } else {
29478  printf(" Convex hull faces: %ld\n", hullsize);
29479  if (meshhulledges > 0l) {
29480  printf(" Convex hull edges: %ld\n", meshhulledges);
29481  }
29482  }
29483  if (b->weighted) { // -w option
29484  printf(" Skipped non-regular points: %ld\n", nonregularcount);
29485  }
29486  printf("\n");
29487 
29488 
29489  if (b->verbose > 0) {
29490  if (b->plc || b->refine) { // -p or -r
29491  if (tetrahedrons->items > 0l) {
29492  qualitystatistics();
29493  }
29494  }
29495  if (tetrahedrons->items > 0l) {
29496  memorystatistics();
29497  }
29498  }
29499 }
29500 
29504 
29508 
29510 // //
29511 // jettisonnodes() Jettison unused or duplicated vertices. //
29512 // //
29513 // Unused points are those input points which are outside the mesh domain or //
29514 // have no connection (isolated) to the mesh. Duplicated points exist for //
29515 // example if the input PLC is read from a .stl mesh file (marked during the //
29516 // Delaunay tetrahedralization step. This routine remove these points from //
29517 // points list. All existing points are reindexed. //
29518 // //
29520 
29521 void tetgenmesh::jettisonnodes()
29522 {
29523  point pointloop;
29524  bool jetflag;
29525  int oldidx, newidx;
29526  int remcount;
29527 
29528  if (!b->quiet) {
29529  printf("Jettisoning redundant points.\n");
29530  }
29531 
29532  points->traversalinit();
29533  pointloop = pointtraverse();
29534  oldidx = newidx = 0; // in->firstnumber;
29535  remcount = 0;
29536  while (pointloop != (point) NULL) {
29537  jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) ||
29538  (pointtype(pointloop) == UNUSEDVERTEX);
29539  if (jetflag) {
29540  // It is a duplicated or unused point, delete it.
29541  pointdealloc(pointloop);
29542  remcount++;
29543  } else {
29544  // Re-index it.
29545  setpointmark(pointloop, newidx + in->firstnumber);
29546  if (in->pointmarkerlist != (int *) NULL) {
29547  if (oldidx < in->numberofpoints) {
29548  // Re-index the point marker as well.
29549  in->pointmarkerlist[newidx] = in->pointmarkerlist[oldidx];
29550  }
29551  }
29552  newidx++;
29553  }
29554  oldidx++;
29555  pointloop = pointtraverse();
29556  }
29557  if (b->verbose) {
29558  printf(" %ld duplicated vertices are removed.\n", dupverts);
29559  printf(" %ld unused vertices are removed.\n", unuverts);
29560  }
29561  dupverts = 0l;
29562  unuverts = 0l;
29563 
29564  // The following line ensures that dead items in the pool of nodes cannot
29565  // be allocated for the new created nodes. This ensures that the input
29566  // nodes will occur earlier in the output files, and have lower indices.
29567  points->deaditemstack = (void *) NULL;
29568 }
29569 
29571 // //
29572 // highorder() Create extra nodes for quadratic subparametric elements. //
29573 // //
29574 // 'highordertable' is an array (size = numberoftetrahedra * 6) for storing //
29575 // high-order nodes of each tetrahedron. This routine is used only when -o2 //
29576 // switch is used. //
29577 // //
29579 
29580 void tetgenmesh::highorder()
29581 {
29582  triface tetloop, worktet, spintet;
29583  point *extralist, *adjextralist;
29584  point torg, tdest, newpoint;
29585  int highorderindex;
29586  int t1ver;
29587  int i, j;
29588 
29589  if (!b->quiet) {
29590  printf("Adding vertices for second-order tetrahedra.\n");
29591  }
29592 
29593  // Initialize the 'highordertable'.
29594  highordertable = new point[tetrahedrons->items * 6];
29595  if (highordertable == (point *) NULL) {
29596  terminatetetgen(this, 1);
29597  }
29598 
29599  // This will overwrite the slot for element markers.
29600  highorderindex = 11;
29601 
29602  // The following line ensures that dead items in the pool of nodes cannot
29603  // be allocated for the extra nodes associated with high order elements.
29604  // This ensures that the primary nodes (at the corners of elements) will
29605  // occur earlier in the output files, and have lower indices, than the
29606  // extra nodes.
29607  points->deaditemstack = (void *) NULL;
29608 
29609  // Assign an entry for each tetrahedron to find its extra nodes. At the
29610  // mean while, initialize all extra nodes be NULL.
29611  i = 0;
29612  tetrahedrons->traversalinit();
29613  tetloop.tet = tetrahedrontraverse();
29614  while (tetloop.tet != (tetrahedron *) NULL) {
29615  tetloop.tet[highorderindex] = (tetrahedron) &highordertable[i];
29616  for (j = 0; j < 6; j++) {
29617  highordertable[i + j] = (point) NULL;
29618  }
29619  i += 6;
29620  tetloop.tet = tetrahedrontraverse();
29621  }
29622 
29623  // To create a unique node on each edge. Loop over all tetrahedra, and
29624  // look at the six edges of each tetrahedron. If the extra node in
29625  // the tetrahedron corresponding to this edge is NULL, create a node
29626  // for this edge, at the same time, set the new node into the extra
29627  // node lists of all other tetrahedra sharing this edge.
29628  tetrahedrons->traversalinit();
29629  tetloop.tet = tetrahedrontraverse();
29630  while (tetloop.tet != (tetrahedron *) NULL) {
29631  // Get the list of extra nodes.
29632  extralist = (point *) tetloop.tet[highorderindex];
29633  worktet.tet = tetloop.tet;
29634  for (i = 0; i < 6; i++) {
29635  if (extralist[i] == (point) NULL) {
29636  // Go to the ith-edge.
29637  worktet.ver = edge2ver[i];
29638  // Create a new point in the middle of this edge.
29639  torg = org(worktet);
29640  tdest = dest(worktet);
29641  makepoint(&newpoint, FREEVOLVERTEX);
29642  for (j = 0; j < 3 + numpointattrib; j++) {
29643  newpoint[j] = 0.5 * (torg[j] + tdest[j]);
29644  }
29645  // Interpolate its metrics.
29646  for (j = 0; j < in->numberofpointmtrs; j++) {
29647  newpoint[pointmtrindex + j] =
29648  0.5 * (torg[pointmtrindex + j] + tdest[pointmtrindex + j]);
29649  }
29650  // Set this point into all extra node lists at this edge.
29651  spintet = worktet;
29652  while (1) {
29653  if (!ishulltet(spintet)) {
29654  adjextralist = (point *) spintet.tet[highorderindex];
29655  adjextralist[ver2edge[spintet.ver]] = newpoint;
29656  }
29657  fnextself(spintet);
29658  if (spintet.tet == worktet.tet) break;
29659  }
29660  } // if (!extralist[i])
29661  } // i
29662  tetloop.tet = tetrahedrontraverse();
29663  }
29664 }
29665 
29667 // //
29668 // indexelements() Index all tetrahedra. //
29669 // //
29670 // Many output functions require that the tetrahedra are indexed. This //
29671 // routine is called when -E option is used. //
29672 // //
29674 
29675 void tetgenmesh::indexelements()
29676 {
29677  triface worktet;
29678  int eindex = b->zeroindex ? 0 : in->firstnumber; // firstindex;
29679  tetrahedrons->traversalinit();
29680  worktet.tet = tetrahedrontraverse();
29681  while (worktet.tet != NULL) {
29682  setelemindex(worktet.tet, eindex);
29683  eindex++;
29684  if (b->metric) { // -m option
29685  // Update the point-to-tet map, so that every point is pointing
29686  // to a real tet, not a fictious one. Used by .p2t file.
29687  tetrahedron tptr = encode(worktet);
29688  for (int i = 0; i < 4; i++) {
29689  setpoint2tet((point) (worktet.tet[4 + i]), tptr);
29690  }
29691  }
29692  worktet.tet = tetrahedrontraverse();
29693  }
29694 }
29695 
29697 // //
29698 // numberedges() Count the number of edges, save in "meshedges". //
29699 // //
29700 // This routine is called when '-p' or '-r', and '-E' options are used. The //
29701 // total number of edges depends on the genus of the input surface mesh. //
29702 // //
29703 // NOTE: This routine must be called after outelements(). So all elements //
29704 // have been indexed. //
29705 // //
29707 
29708 void tetgenmesh::numberedges()
29709 {
29710  triface worktet, spintet;
29711  int ishulledge;
29712  int t1ver;
29713  int i;
29714 
29715  meshedges = meshhulledges = 0l;
29716 
29717  tetrahedrons->traversalinit();
29718  worktet.tet = tetrahedrontraverse();
29719  while (worktet.tet != NULL) {
29720  for (i = 0; i < 6; i++) {
29721  worktet.ver = edge2ver[i];
29722  ishulledge = 0;
29723  fnext(worktet, spintet);
29724  do {
29725  if (!ishulltet(spintet)) {
29726  if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
29727  } else {
29728  ishulledge = 1;
29729  }
29730  fnextself(spintet);
29731  } while (spintet.tet != worktet.tet);
29732  if (spintet.tet == worktet.tet) {
29733  meshedges++;
29734  if (ishulledge) meshhulledges++;
29735  }
29736  }
29737  infect(worktet);
29738  worktet.tet = tetrahedrontraverse();
29739  }
29740 }
29741 
29743 // //
29744 // outnodes() Output the points to a .node file or a tetgenio structure. //
29745 // //
29746 // Note: each point has already been numbered on input (the first index is //
29747 // 'in->firstnumber'). //
29748 // //
29750 
29751 void tetgenmesh::outnodes(tetgenio* out)
29752 {
29753  FILE *outfile = NULL;
29754  char outnodefilename[FILENAMESIZE];
29755  face parentsh;
29756  point pointloop;
29757  int nextras, bmark, marker = 0, weightDT = 0;
29758  int coordindex, attribindex;
29759  int pointnumber, firstindex;
29760  int index, i;
29761 
29762  if (out == (tetgenio *) NULL) {
29763  strcpy(outnodefilename, b->outfilename);
29764  strcat(outnodefilename, ".node");
29765  }
29766 
29767  if (!b->quiet) {
29768  if (out == (tetgenio *) NULL) {
29769  printf("Writing %s.\n", outnodefilename);
29770  } else {
29771  printf("Writing nodes.\n");
29772  }
29773  }
29774 
29775  nextras = numpointattrib;
29776  if (b->weighted) { // -w
29777  if (b->weighted_param == 0) weightDT = 1; // Weighted DT.
29778  }
29779 
29780  bmark = !b->nobound && in->pointmarkerlist;
29781 
29782  if (out == (tetgenio *) NULL) {
29783  outfile = fopen(outnodefilename, "w");
29784  if (outfile == (FILE *) NULL) {
29785  printf("File I/O Error: Cannot create file %s.\n", outnodefilename);
29786  terminatetetgen(this, 1);
29787  }
29788  // Number of points, number of dimensions, number of point attributes,
29789  // and number of boundary markers (zero or one).
29790  fprintf(outfile, "%ld %d %d %d\n", points->items, 3, nextras, bmark);
29791  } else {
29792  // Allocate space for 'pointlist';
29793  out->pointlist = new REAL[points->items * 3];
29794  if (out->pointlist == (REAL *) NULL) {
29795  printf("Error: Out of memory.\n");
29796  terminatetetgen(this, 1);
29797  }
29798  // Allocate space for 'pointattributelist' if necessary;
29799  if (nextras > 0) {
29800  out->pointattributelist = new REAL[points->items * nextras];
29801  if (out->pointattributelist == (REAL *) NULL) {
29802  printf("Error: Out of memory.\n");
29803  terminatetetgen(this, 1);
29804  }
29805  }
29806  // Allocate space for 'pointmarkerlist' if necessary;
29807  if (bmark) {
29808  out->pointmarkerlist = new int[points->items];
29809  if (out->pointmarkerlist == (int *) NULL) {
29810  printf("Error: Out of memory.\n");
29811  terminatetetgen(this, 1);
29812  }
29813  }
29814  if (b->psc) {
29815  out->pointparamlist = new tetgenio::pointparam[points->items];
29816  if (out->pointparamlist == NULL) {
29817  printf("Error: Out of memory.\n");
29818  terminatetetgen(this, 1);
29819  }
29820  }
29821  out->numberofpoints = points->items;
29822  out->numberofpointattributes = nextras;
29823  coordindex = 0;
29824  attribindex = 0;
29825  }
29826 
29827  // Determine the first index (0 or 1).
29828  firstindex = b->zeroindex ? 0 : in->firstnumber;
29829 
29830  points->traversalinit();
29831  pointloop = pointtraverse();
29832  pointnumber = firstindex; // in->firstnumber;
29833  index = 0;
29834  while (pointloop != (point) NULL) {
29835  if (bmark) {
29836  // Default the vertex has a zero marker.
29837  marker = 0;
29838  // Is it an input vertex?
29839  if (index < in->numberofpoints) {
29840  // Input point's marker is directly copied to output.
29841  marker = in->pointmarkerlist[index];
29842  } else {
29843  if ((pointtype(pointloop) == FREESEGVERTEX) ||
29844  (pointtype(pointloop) == FREEFACETVERTEX)) {
29845  sdecode(point2sh(pointloop), parentsh);
29846  if (parentsh.sh != NULL) {
29847  marker = shellmark(parentsh);
29848  }
29849  } // if (pointtype(...))
29850  }
29851  }
29852  if (out == (tetgenio *) NULL) {
29853  // Point number, x, y and z coordinates.
29854  fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber,
29855  pointloop[0], pointloop[1], pointloop[2]);
29856  for (i = 0; i < nextras; i++) {
29857  // Write an attribute.
29858  if ((i == 0) && weightDT) {
29859  fprintf(outfile, " %.17g", pointloop[0] * pointloop[0] +
29860  pointloop[1] * pointloop[1] + pointloop[2] * pointloop[2]
29861  - pointloop[3 + i]);
29862  } else {
29863  fprintf(outfile, " %.17g", pointloop[3 + i]);
29864  }
29865  }
29866  if (bmark) {
29867  // Write the boundary marker.
29868  fprintf(outfile, " %d", marker);
29869  }
29870  if (b->psc) {
29871  fprintf(outfile, " %.8g %.8g %d", pointgeomuv(pointloop, 0),
29872  pointgeomuv(pointloop, 1), pointgeomtag(pointloop));
29873  if (pointtype(pointloop) == RIDGEVERTEX) {
29874  fprintf(outfile, " 0");
29875  } else if (pointtype(pointloop) == ACUTEVERTEX) {
29876  fprintf(outfile, " 0");
29877  } else if (pointtype(pointloop) == FREESEGVERTEX) {
29878  fprintf(outfile, " 1");
29879  } else if (pointtype(pointloop) == FREEFACETVERTEX) {
29880  fprintf(outfile, " 2");
29881  } else if (pointtype(pointloop) == FREEVOLVERTEX) {
29882  fprintf(outfile, " 3");
29883  } else {
29884  fprintf(outfile, " -1"); // Unknown type.
29885  }
29886  }
29887  fprintf(outfile, "\n");
29888  } else {
29889  // X, y, and z coordinates.
29890  out->pointlist[coordindex++] = pointloop[0];
29891  out->pointlist[coordindex++] = pointloop[1];
29892  out->pointlist[coordindex++] = pointloop[2];
29893  // Point attributes.
29894  for (i = 0; i < nextras; i++) {
29895  // Output an attribute.
29896  if ((i == 0) && weightDT) {
29897  out->pointattributelist[attribindex++] =
29898  pointloop[0] * pointloop[0] + pointloop[1] * pointloop[1] +
29899  pointloop[2] * pointloop[2] - pointloop[3 + i];
29900  } else {
29901  out->pointattributelist[attribindex++] = pointloop[3 + i];
29902  }
29903  }
29904  if (bmark) {
29905  // Output the boundary marker.
29906  out->pointmarkerlist[index] = marker;
29907  }
29908  if (b->psc) {
29909  out->pointparamlist[index].uv[0] = pointgeomuv(pointloop, 0);
29910  out->pointparamlist[index].uv[1] = pointgeomuv(pointloop, 1);
29911  out->pointparamlist[index].tag = pointgeomtag(pointloop);
29912  if (pointtype(pointloop) == RIDGEVERTEX) {
29913  out->pointparamlist[index].type = 0;
29914  } else if (pointtype(pointloop) == ACUTEVERTEX) {
29915  out->pointparamlist[index].type = 0;
29916  } else if (pointtype(pointloop) == FREESEGVERTEX) {
29917  out->pointparamlist[index].type = 1;
29918  } else if (pointtype(pointloop) == FREEFACETVERTEX) {
29919  out->pointparamlist[index].type = 2;
29920  } else if (pointtype(pointloop) == FREEVOLVERTEX) {
29921  out->pointparamlist[index].type = 3;
29922  } else {
29923  out->pointparamlist[index].type = -1; // Unknown type.
29924  }
29925  }
29926  }
29927  pointloop = pointtraverse();
29928  pointnumber++;
29929  index++;
29930  }
29931 
29932  if (out == (tetgenio *) NULL) {
29933  fprintf(outfile, "# Generated by %s\n", b->commandline);
29934  fclose(outfile);
29935  }
29936 }
29937 
29939 // //
29940 // outmetrics() Output the metric to a file (*.mtr) or a tetgenio obj. //
29941 // //
29943 
29944 void tetgenmesh::outmetrics(tetgenio* out)
29945 {
29946  FILE *outfile = NULL;
29947  char outmtrfilename[FILENAMESIZE];
29948  point ptloop;
29949  int mtrindex = 0;
29950  int i;
29951  int msize = (sizeoftensor - useinsertradius);
29952  if (msize == 0) {
29953  return;
29954  }
29955 
29956  if (out == (tetgenio *) NULL) {
29957  strcpy(outmtrfilename, b->outfilename);
29958  strcat(outmtrfilename, ".mtr");
29959  }
29960 
29961  if (!b->quiet) {
29962  if (out == (tetgenio *) NULL) {
29963  printf("Writing %s.\n", outmtrfilename);
29964  } else {
29965  printf("Writing metrics.\n");
29966  }
29967  }
29968 
29969  if (out == (tetgenio *) NULL) {
29970  outfile = fopen(outmtrfilename, "w");
29971  if (outfile == (FILE *) NULL) {
29972  printf("File I/O Error: Cannot create file %s.\n", outmtrfilename);
29973  terminatetetgen(this, 3);
29974  }
29975  // Number of points, number of point metrices,
29976  fprintf(outfile, "%ld %d\n", points->items, msize);
29977  } else {
29978  // Allocate space for 'pointmtrlist'.
29979  out->numberofpointmtrs = msize;
29980  out->pointmtrlist = new REAL[points->items * msize];
29981  if (out->pointmtrlist == (REAL *) NULL) {
29982  terminatetetgen(this, 1);
29983  }
29984  }
29985 
29986  points->traversalinit();
29987  ptloop = pointtraverse();
29988  while (ptloop != (point) NULL) {
29989  if (out == (tetgenio *) NULL) {
29990  for (i = 0; i < msize; i++) {
29991  fprintf(outfile, " %-16.8e", ptloop[pointmtrindex + i]);
29992  }
29993  fprintf(outfile, "\n");
29994  } else {
29995  for (i = 0; i < msize; i++) {
29996  out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex + i];
29997  }
29998  }
29999  ptloop = pointtraverse();
30000  }
30001 
30002  // Output the point-to-tet map.
30003  if (out == (tetgenio *) NULL) {
30004  strcpy(outmtrfilename, b->outfilename);
30005  strcat(outmtrfilename, ".p2t");
30006  }
30007 
30008  if (!b->quiet) {
30009  if (out == (tetgenio *) NULL) {
30010  printf("Writing %s.\n", outmtrfilename);
30011  } else {
30012  printf("Writing point-to-tet map.\n");
30013  }
30014  }
30015 
30016  if (out == (tetgenio *) NULL) {
30017  outfile = fopen(outmtrfilename, "w");
30018  if (outfile == (FILE *) NULL) {
30019  printf("File I/O Error: Cannot create file %s.\n", outmtrfilename);
30020  terminatetetgen(this, 3);
30021  }
30022  // Number of points,
30023  //fprintf(outfile, "%ld\n", points->items);
30024  } else {
30025  // Allocate space for 'point2tetlist'.
30026  out->point2tetlist = new int[points->items];
30027  if (out->point2tetlist == (int *) NULL) {
30028  terminatetetgen(this, 1);
30029  }
30030  }
30031 
30032  // The list of tetrahedra must be indexed.
30033  if (bgm != NULL) {
30034  bgm->indexelements();
30035  }
30036  // Determine the first index (0 or 1).
30037  int firstindex = b->zeroindex ? 0 : in->firstnumber;
30038  int pointindex = firstindex;
30039  i = 0;
30040 
30041  triface parenttet;
30042  points->traversalinit();
30043  ptloop = pointtraverse();
30044  while (ptloop != (point) NULL) {
30045  if (bgm != NULL) {
30046  bgm->decode(point2bgmtet(ptloop), parenttet);
30047  } else {
30048  decode(point2tet(ptloop), parenttet);
30049  }
30050  if (out == (tetgenio *) NULL) {
30051  fprintf(outfile, "%d %d\n", pointindex, elemindex(parenttet.tet));
30052  } else {
30053  out->point2tetlist[i] = elemindex(parenttet.tet);
30054  }
30055  pointindex++;
30056  i++;
30057  ptloop = pointtraverse();
30058  }
30059 
30060  if (out == (tetgenio *) NULL) {
30061  fprintf(outfile, "# Generated by %s\n", b->commandline);
30062  fclose(outfile);
30063  }
30064 }
30065 
30067 // //
30068 // outelements() Output the tetrahedra to an .ele file or a tetgenio //
30069 // structure. //
30070 // //
30071 // This routine also indexes all tetrahedra (exclusing hull tets) (from in-> //
30072 // firstnumber). The total number of mesh edges is counted in 'meshedges'. //
30073 // //
30075 
30076 void tetgenmesh::outelements(tetgenio* out)
30077 {
30078  FILE *outfile = NULL;
30079  char outelefilename[FILENAMESIZE];
30080  tetrahedron* tptr;
30081  point p1, p2, p3, p4;
30082  point *extralist;
30083  REAL *talist = NULL;
30084  int *tlist = NULL;
30085  long ntets;
30086  int firstindex, shift;
30087  int pointindex, attribindex;
30088  int highorderindex = 11;
30089  int elementnumber;
30090  int eextras;
30091  int i;
30092 
30093  if (out == (tetgenio *) NULL) {
30094  strcpy(outelefilename, b->outfilename);
30095  strcat(outelefilename, ".ele");
30096  }
30097 
30098  if (!b->quiet) {
30099  if (out == (tetgenio *) NULL) {
30100  printf("Writing %s.\n", outelefilename);
30101  } else {
30102  printf("Writing elements.\n");
30103  }
30104  }
30105 
30106  // The number of tets excluding hull tets.
30107  ntets = tetrahedrons->items - hullsize;
30108 
30109  eextras = numelemattrib;
30110  if (out == (tetgenio *) NULL) {
30111  outfile = fopen(outelefilename, "w");
30112  if (outfile == (FILE *) NULL) {
30113  printf("File I/O Error: Cannot create file %s.\n", outelefilename);
30114  terminatetetgen(this, 1);
30115  }
30116  // Number of tetras, points per tetra, attributes per tetra.
30117  fprintf(outfile, "%ld %d %d\n", ntets, b->order == 1 ? 4 : 10, eextras);
30118  } else {
30119  // Allocate memory for output tetrahedra.
30120  out->tetrahedronlist = new int[ntets * (b->order == 1 ? 4 : 10)];
30121  if (out->tetrahedronlist == (int *) NULL) {
30122  printf("Error: Out of memory.\n");
30123  terminatetetgen(this, 1);
30124  }
30125  // Allocate memory for output tetrahedron attributes if necessary.
30126  if (eextras > 0) {
30127  out->tetrahedronattributelist = new REAL[ntets * eextras];
30128  if (out->tetrahedronattributelist == (REAL *) NULL) {
30129  printf("Error: Out of memory.\n");
30130  terminatetetgen(this, 1);
30131  }
30132  }
30133  out->numberoftetrahedra = ntets;
30134  out->numberofcorners = b->order == 1 ? 4 : 10;
30135  out->numberoftetrahedronattributes = eextras;
30136  tlist = out->tetrahedronlist;
30137  talist = out->tetrahedronattributelist;
30138  pointindex = 0;
30139  attribindex = 0;
30140  }
30141 
30142  // Determine the first index (0 or 1).
30143  firstindex = b->zeroindex ? 0 : in->firstnumber;
30144  shift = 0; // Default no shift.
30145  if ((in->firstnumber == 1) && (firstindex == 0)) {
30146  shift = 1; // Shift the output indices by 1.
30147  }
30148 
30149  tetrahedrons->traversalinit();
30150  tptr = tetrahedrontraverse();
30151  elementnumber = firstindex; // in->firstnumber;
30152  while (tptr != (tetrahedron *) NULL) {
30153  if (!b->reversetetori) {
30154  p1 = (point) tptr[4];
30155  p2 = (point) tptr[5];
30156  } else {
30157  p1 = (point) tptr[5];
30158  p2 = (point) tptr[4];
30159  }
30160  p3 = (point) tptr[6];
30161  p4 = (point) tptr[7];
30162  if (out == (tetgenio *) NULL) {
30163  // Tetrahedron number, indices for four points.
30164  fprintf(outfile, "%5d %5d %5d %5d %5d", elementnumber,
30165  pointmark(p1) - shift, pointmark(p2) - shift,
30166  pointmark(p3) - shift, pointmark(p4) - shift);
30167  if (b->order == 2) {
30168  extralist = (point *) tptr[highorderindex];
30169  // indices for six extra points.
30170  fprintf(outfile, " %5d %5d %5d %5d %5d %5d",
30171  pointmark(extralist[0]) - shift, pointmark(extralist[1]) - shift,
30172  pointmark(extralist[2]) - shift, pointmark(extralist[3]) - shift,
30173  pointmark(extralist[4]) - shift, pointmark(extralist[5]) - shift);
30174  }
30175  for (i = 0; i < eextras; i++) {
30176  fprintf(outfile, " %.17g", elemattribute(tptr, i));
30177  }
30178  fprintf(outfile, "\n");
30179  } else {
30180  tlist[pointindex++] = pointmark(p1) - shift;
30181  tlist[pointindex++] = pointmark(p2) - shift;
30182  tlist[pointindex++] = pointmark(p3) - shift;
30183  tlist[pointindex++] = pointmark(p4) - shift;
30184  if (b->order == 2) {
30185  extralist = (point *) tptr[highorderindex];
30186  tlist[pointindex++] = pointmark(extralist[0]) - shift;
30187  tlist[pointindex++] = pointmark(extralist[1]) - shift;
30188  tlist[pointindex++] = pointmark(extralist[2]) - shift;
30189  tlist[pointindex++] = pointmark(extralist[3]) - shift;
30190  tlist[pointindex++] = pointmark(extralist[4]) - shift;
30191  tlist[pointindex++] = pointmark(extralist[5]) - shift;
30192  }
30193  for (i = 0; i < eextras; i++) {
30194  talist[attribindex++] = elemattribute(tptr, i);
30195  }
30196  }
30197  // Remember the index of this element (for counting edges).
30198  setelemindex(tptr, elementnumber);
30199  if (b->metric) { // -m option
30200  // Update the point-to-tet map, so that every point is pointing
30201  // to a real tet, not a fictious one. Used by .p2t file.
30202  for (int i = 0; i < 4; i++) {
30203  setpoint2tet((point) (tptr[4 + i]), (tetrahedron) tptr);
30204  }
30205  }
30206  tptr = tetrahedrontraverse();
30207  elementnumber++;
30208  }
30209 
30210 
30211  if (out == (tetgenio *) NULL) {
30212  fprintf(outfile, "# Generated by %s\n", b->commandline);
30213  fclose(outfile);
30214  }
30215 }
30216 
30218 // //
30219 // outfaces() Output all faces to a .face file or a tetgenio object. //
30220 // //
30222 
30223 void tetgenmesh::outfaces(tetgenio* out)
30224 {
30225  FILE *outfile = NULL;
30226  char facefilename[FILENAMESIZE];
30227  triface tface, tsymface;
30228  face checkmark;
30229  point torg, tdest, tapex;
30230  long ntets, faces;
30231  int *elist = NULL, *emlist = NULL;
30232  int neigh1 = 0, neigh2 = 0;
30233  int marker = 0;
30234  int firstindex, shift;
30235  int facenumber;
30236  int index = 0;
30237 
30238  // For -o2 option.
30239  triface workface;
30240  point *extralist, pp[3] = {0,0,0};
30241  int highorderindex = 11;
30242  int o2index = 0, i;
30243 
30244  // For -nn option.
30245  int *tet2facelist = NULL;
30246  int tidx;
30247 
30248  if (out == (tetgenio *) NULL) {
30249  strcpy(facefilename, b->outfilename);
30250  strcat(facefilename, ".face");
30251  }
30252 
30253  if (!b->quiet) {
30254  if (out == (tetgenio *) NULL) {
30255  printf("Writing %s.\n", facefilename);
30256  } else {
30257  printf("Writing faces.\n");
30258  }
30259  }
30260 
30261  ntets = tetrahedrons->items - hullsize;
30262  faces = (ntets * 4l + hullsize) / 2l;
30263 
30264  if (out == (tetgenio *) NULL) {
30265  outfile = fopen(facefilename, "w");
30266  if (outfile == (FILE *) NULL) {
30267  printf("File I/O Error: Cannot create file %s.\n", facefilename);
30268  terminatetetgen(this, 1);
30269  }
30270  fprintf(outfile, "%ld %d\n", faces, !b->nobound);
30271  } else {
30272  // Allocate memory for 'trifacelist'.
30273  out->trifacelist = new int[faces * 3];
30274  if (out->trifacelist == (int *) NULL) {
30275  printf("Error: Out of memory.\n");
30276  terminatetetgen(this, 1);
30277  }
30278  if (b->order == 2) {
30279  out->o2facelist = new int[faces * 3];
30280  }
30281  // Allocate memory for 'trifacemarkerlist' if necessary.
30282  if (!b->nobound) {
30283  out->trifacemarkerlist = new int[faces];
30284  if (out->trifacemarkerlist == (int *) NULL) {
30285  printf("Error: Out of memory.\n");
30286  terminatetetgen(this, 1);
30287  }
30288  }
30289  if (b->neighout > 1) {
30290  // '-nn' switch.
30291  out->face2tetlist = new int[faces * 2];
30292  if (out->face2tetlist == (int *) NULL) {
30293  printf("Error: Out of memory.\n");
30294  terminatetetgen(this, 1);
30295  }
30296  }
30297  out->numberoftrifaces = faces;
30298  elist = out->trifacelist;
30299  emlist = out->trifacemarkerlist;
30300  }
30301 
30302  if (b->neighout > 1) { // -nn option
30303  // Output the tetrahedron-to-face map.
30304  tet2facelist = new int[ntets * 4];
30305  }
30306 
30307  // Determine the first index (0 or 1).
30308  firstindex = b->zeroindex ? 0 : in->firstnumber;
30309  shift = 0; // Default no shiftment.
30310  if ((in->firstnumber == 1) && (firstindex == 0)) {
30311  shift = 1; // Shift the output indices by 1.
30312  }
30313 
30314  tetrahedrons->traversalinit();
30315  tface.tet = tetrahedrontraverse();
30316  facenumber = firstindex; // in->firstnumber;
30317  // To loop over the set of faces, loop over all tetrahedra, and look at
30318  // the four faces of each one. If its adjacent tet is a hull tet,
30319  // operate on the face, otherwise, operate on the face only if the
30320  // current tet has a smaller index than its neighbor.
30321  while (tface.tet != (tetrahedron *) NULL) {
30322  for (tface.ver = 0; tface.ver < 4; tface.ver ++) {
30323  fsym(tface, tsymface);
30324  if (ishulltet(tsymface) ||
30325  (elemindex(tface.tet) < elemindex(tsymface.tet))) {
30326  torg = org(tface);
30327  tdest = dest(tface);
30328  tapex = apex(tface);
30329  if (b->order == 2) { // -o2
30330  // Get the three extra vertices on edges.
30331  extralist = (point *) (tface.tet[highorderindex]);
30332  // The extra vertices are on edges opposite the corners.
30333  enext(tface, workface);
30334  for (i = 0; i < 3; i++) {
30335  pp[i] = extralist[ver2edge[workface.ver]];
30336  enextself(workface);
30337  }
30338  }
30339  if (!b->nobound) {
30340  // Get the boundary marker of this face.
30341  if (b->plc || b->refine) {
30342  // Shell face is used.
30343  tspivot(tface, checkmark);
30344  if (checkmark.sh == NULL) {
30345  marker = 0; // It is an inner face. It's marker is 0.
30346  } else {
30347  marker = shellmark(checkmark);
30348  }
30349  } else {
30350  // Shell face is not used, only distinguish outer and inner face.
30351  marker = (int) ishulltet(tsymface);
30352  }
30353  }
30354  if (b->neighout > 1) {
30355  // '-nn' switch. Output adjacent tets indices.
30356  if (!ishulltet(tface)) {
30357  neigh1 = elemindex(tface.tet);
30358  } else {
30359  neigh1 = -1;
30360  }
30361  if (!ishulltet(tsymface)) {
30362  neigh2 = elemindex(tsymface.tet);
30363  } else {
30364  neigh2 = -1;
30365  }
30366  // Fill the tetrahedron-to-face map.
30367  tidx = elemindex(tface.tet) - firstindex;
30368  tet2facelist[tidx * 4 + tface.ver] = facenumber;
30369  if (!ishulltet(tsymface)) {
30370  tidx = elemindex(tsymface.tet) - firstindex;
30371  tet2facelist[tidx * 4 + (tsymface.ver & 3)] = facenumber;
30372  }
30373  }
30374  if (out == (tetgenio *) NULL) {
30375  // Face number, indices of three vertices.
30376  fprintf(outfile, "%5d %4d %4d %4d", facenumber,
30377  pointmark(torg) - shift, pointmark(tdest) - shift,
30378  pointmark(tapex) - shift);
30379  if (b->order == 2) { // -o2
30380  fprintf(outfile, " %4d %4d %4d", pointmark(pp[0]) - shift,
30381  pointmark(pp[1]) - shift, pointmark(pp[2]) - shift);
30382  }
30383  if (!b->nobound) {
30384  // Output a boundary marker.
30385  fprintf(outfile, " %d", marker);
30386  }
30387  if (b->neighout > 1) {
30388  fprintf(outfile, " %5d %5d", neigh1, neigh2);
30389  }
30390  fprintf(outfile, "\n");
30391  } else {
30392  // Output indices of three vertices.
30393  elist[index++] = pointmark(torg) - shift;
30394  elist[index++] = pointmark(tdest) - shift;
30395  elist[index++] = pointmark(tapex) - shift;
30396  if (b->order == 2) { // -o2
30397  out->o2facelist[o2index++] = pointmark(pp[0]) - shift;
30398  out->o2facelist[o2index++] = pointmark(pp[1]) - shift;
30399  out->o2facelist[o2index++] = pointmark(pp[2]) - shift;
30400  }
30401  if (!b->nobound) {
30402  emlist[facenumber - in->firstnumber] = marker;
30403  }
30404  if (b->neighout > 1) {
30405  out->face2tetlist[(facenumber - in->firstnumber) * 2] = neigh1;
30406  out->face2tetlist[(facenumber - in->firstnumber) * 2 + 1] = neigh2;
30407  }
30408  }
30409  facenumber++;
30410  }
30411  }
30412  tface.tet = tetrahedrontraverse();
30413  }
30414 
30415  if (out == (tetgenio *) NULL) {
30416  fprintf(outfile, "# Generated by %s\n", b->commandline);
30417  fclose(outfile);
30418  }
30419 
30420  if (b->neighout > 1) { // -nn option
30421  // Output the tetrahedron-to-face map.
30422  if (out == (tetgenio *) NULL) {
30423  strcpy(facefilename, b->outfilename);
30424  strcat(facefilename, ".t2f");
30425  }
30426  if (!b->quiet) {
30427  if (out == (tetgenio *) NULL) {
30428  printf("Writing %s.\n", facefilename);
30429  } else {
30430  printf("Writing tetrahedron-to-face map.\n");
30431  }
30432  }
30433  if (out == (tetgenio *) NULL) {
30434  outfile = fopen(facefilename, "w");
30435  for (tidx = 0; tidx < ntets; tidx++) {
30436  index = tidx * 4;
30437  fprintf(outfile, "%4d %d %d %d %d\n", tidx + in->firstnumber,
30438  tet2facelist[index], tet2facelist[index+1],
30439  tet2facelist[index+2], tet2facelist[index+3]);
30440  }
30441  fclose(outfile);
30442  delete [] tet2facelist;
30443  } else {
30444  // Simply copy the address of the list to the output.
30445  out->tet2facelist = tet2facelist;
30446  }
30447  }
30448 }
30449 
30451 // //
30452 // outhullfaces() Output hull faces to a .face file or a tetgenio object. //
30453 // //
30454 // The normal of each face is pointing to the outside of the domain. //
30455 // //
30457 
30458 void tetgenmesh::outhullfaces(tetgenio* out)
30459 {
30460  FILE *outfile = NULL;
30461  char facefilename[FILENAMESIZE];
30462  triface hulltet;
30463  point torg, tdest, tapex;
30464  int *elist = NULL;
30465  int firstindex, shift;
30466  int facenumber;
30467  int index;
30468 
30469  if (out == (tetgenio *) NULL) {
30470  strcpy(facefilename, b->outfilename);
30471  strcat(facefilename, ".face");
30472  }
30473 
30474  if (!b->quiet) {
30475  if (out == (tetgenio *) NULL) {
30476  printf("Writing %s.\n", facefilename);
30477  } else {
30478  printf("Writing faces.\n");
30479  }
30480  }
30481 
30482  if (out == (tetgenio *) NULL) {
30483  outfile = fopen(facefilename, "w");
30484  if (outfile == (FILE *) NULL) {
30485  printf("File I/O Error: Cannot create file %s.\n", facefilename);
30486  terminatetetgen(this, 1);
30487  }
30488  fprintf(outfile, "%ld 0\n", hullsize);
30489  } else {
30490  // Allocate memory for 'trifacelist'.
30491  out->trifacelist = new int[hullsize * 3];
30492  if (out->trifacelist == (int *) NULL) {
30493  printf("Error: Out of memory.\n");
30494  terminatetetgen(this, 1);
30495  }
30496  out->numberoftrifaces = hullsize;
30497  elist = out->trifacelist;
30498  index = 0;
30499  }
30500 
30501  // Determine the first index (0 or 1).
30502  firstindex = b->zeroindex ? 0 : in->firstnumber;
30503  shift = 0; // Default no shiftment.
30504  if ((in->firstnumber == 1) && (firstindex == 0)) {
30505  shift = 1; // Shift the output indices by 1.
30506  }
30507 
30508  tetrahedrons->traversalinit();
30509  hulltet.tet = alltetrahedrontraverse();
30510  facenumber = firstindex;
30511  while (hulltet.tet != (tetrahedron *) NULL) {
30512  if (ishulltet(hulltet)) {
30513  torg = (point) hulltet.tet[4];
30514  tdest = (point) hulltet.tet[5];
30515  tapex = (point) hulltet.tet[6];
30516  if (out == (tetgenio *) NULL) {
30517  // Face number, indices of three vertices.
30518  fprintf(outfile, "%5d %4d %4d %4d", facenumber,
30519  pointmark(torg) - shift, pointmark(tdest) - shift,
30520  pointmark(tapex) - shift);
30521  fprintf(outfile, "\n");
30522  } else {
30523  // Output indices of three vertices.
30524  elist[index++] = pointmark(torg) - shift;
30525  elist[index++] = pointmark(tdest) - shift;
30526  elist[index++] = pointmark(tapex) - shift;
30527  }
30528  facenumber++;
30529  }
30530  hulltet.tet = alltetrahedrontraverse();
30531  }
30532 
30533  if (out == (tetgenio *) NULL) {
30534  fprintf(outfile, "# Generated by %s\n", b->commandline);
30535  fclose(outfile);
30536  }
30537 }
30538 
30540 // //
30541 // outsubfaces() Output subfaces (i.e. boundary faces) to a .face file or //
30542 // a tetgenio structure. //
30543 // //
30544 // The boundary faces are found in 'subfaces'. For listing triangle vertices //
30545 // in the same sense for all triangles in the mesh, the direction determined //
30546 // by right-hand rule is pointer to the inside of the volume. //
30547 // //
30549 
30550 void tetgenmesh::outsubfaces(tetgenio* out)
30551 {
30552  FILE *outfile = NULL;
30553  char facefilename[FILENAMESIZE];
30554  int *elist = NULL;
30555  int *emlist = NULL;
30556  int index = 0, index1 = 0, index2 = 0;
30557  triface abuttingtet;
30558  face faceloop;
30559  point torg, tdest, tapex;
30560  int marker = 0;
30561  int firstindex, shift;
30562  int neigh1 = 0, neigh2 = 0;
30563  int facenumber;
30564 
30565  // For -o2 option.
30566  triface workface;
30567  point *extralist, pp[3] = {0,0,0};
30568  int highorderindex = 11;
30569  int o2index = 0, i;
30570 
30571  int t1ver; // used by fsymself()
30572 
30573  if (out == (tetgenio *) NULL) {
30574  strcpy(facefilename, b->outfilename);
30575  strcat(facefilename, ".face");
30576  }
30577 
30578  if (!b->quiet) {
30579  if (out == (tetgenio *) NULL) {
30580  printf("Writing %s.\n", facefilename);
30581  } else {
30582  printf("Writing faces.\n");
30583  }
30584  }
30585 
30586  if (out == (tetgenio *) NULL) {
30587  outfile = fopen(facefilename, "w");
30588  if (outfile == (FILE *) NULL) {
30589  printf("File I/O Error: Cannot create file %s.\n", facefilename);
30590  terminatetetgen(this, 3);
30591  }
30592  // Number of subfaces.
30593  fprintf(outfile, "%ld %d\n", subfaces->items, !b->nobound);
30594  } else {
30595  // Allocate memory for 'trifacelist'.
30596  out->trifacelist = new int[subfaces->items * 3];
30597  if (out->trifacelist == (int *) NULL) {
30598  terminatetetgen(this, 1);
30599  }
30600  if (b->order == 2) {
30601  out->o2facelist = new int[subfaces->items * 3];
30602  }
30603  if (!b->nobound) {
30604  // Allocate memory for 'trifacemarkerlist'.
30605  out->trifacemarkerlist = new int[subfaces->items];
30606  if (out->trifacemarkerlist == (int *) NULL) {
30607  terminatetetgen(this, 1);
30608  }
30609  }
30610  if (b->neighout > 1) {
30611  // '-nn' switch.
30612  out->face2tetlist = new int[subfaces->items * 2];
30613  if (out->face2tetlist == (int *) NULL) {
30614  terminatetetgen(this, 1);
30615  }
30616  }
30617  out->numberoftrifaces = subfaces->items;
30618  elist = out->trifacelist;
30619  emlist = out->trifacemarkerlist;
30620  }
30621 
30622  // Determine the first index (0 or 1).
30623  firstindex = b->zeroindex ? 0 : in->firstnumber;
30624  shift = 0; // Default no shiftment.
30625  if ((in->firstnumber == 1) && (firstindex == 0)) {
30626  shift = 1; // Shift the output indices by 1.
30627  }
30628 
30629  subfaces->traversalinit();
30630  faceloop.sh = shellfacetraverse(subfaces);
30631  facenumber = firstindex; // in->firstnumber;
30632  while (faceloop.sh != (shellface *) NULL) {
30633  stpivot(faceloop, abuttingtet);
30634  // If there is a tetrahedron containing this subface, orient it so
30635  // that the normal of this face points to inside of the volume by
30636  // right-hand rule.
30637  if (abuttingtet.tet != NULL) {
30638  if (ishulltet(abuttingtet)) {
30639  fsymself(abuttingtet);
30640  }
30641  }
30642  if (abuttingtet.tet != NULL) {
30643  torg = org(abuttingtet);
30644  tdest = dest(abuttingtet);
30645  tapex = apex(abuttingtet);
30646  if (b->order == 2) { // -o2
30647  // Get the three extra vertices on edges.
30648  extralist = (point *) (abuttingtet.tet[highorderindex]);
30649  workface = abuttingtet;
30650  for (i = 0; i < 3; i++) {
30651  pp[i] = extralist[ver2edge[workface.ver]];
30652  enextself(workface);
30653  }
30654  }
30655  } else {
30656  // This may happen when only a surface mesh be generated.
30657  torg = sorg(faceloop);
30658  tdest = sdest(faceloop);
30659  tapex = sapex(faceloop);
30660  if (b->order == 2) { // -o2
30661  // There is no extra node list available.
30662  pp[0] = torg;
30663  pp[1] = tdest;
30664  pp[2] = tapex;
30665  }
30666  }
30667  if (!b->nobound) {
30668  marker = shellmark(faceloop);
30669  }
30670  if (b->neighout > 1) {
30671  // '-nn' switch. Output adjacent tets indices.
30672  neigh1 = -1;
30673  neigh2 = -1;
30674  stpivot(faceloop, abuttingtet);
30675  if (abuttingtet.tet != NULL) {
30676  if (!ishulltet(abuttingtet)) {
30677  neigh1 = elemindex(abuttingtet.tet);
30678  }
30679  fsymself(abuttingtet);
30680  if (!ishulltet(abuttingtet)) {
30681  neigh2 = elemindex(abuttingtet.tet);
30682  }
30683  }
30684  }
30685  if (out == (tetgenio *) NULL) {
30686  fprintf(outfile, "%5d %4d %4d %4d", facenumber,
30687  pointmark(torg) - shift, pointmark(tdest) - shift,
30688  pointmark(tapex) - shift);
30689  if (b->order == 2) { // -o2
30690  fprintf(outfile, " %4d %4d %4d", pointmark(pp[0]) - shift,
30691  pointmark(pp[1]) - shift, pointmark(pp[2]) - shift);
30692  }
30693  if (!b->nobound) {
30694  fprintf(outfile, " %d", marker);
30695  }
30696  if (b->neighout > 1) {
30697  fprintf(outfile, " %5d %5d", neigh1, neigh2);
30698  }
30699  fprintf(outfile, "\n");
30700  } else {
30701  // Output three vertices of this face;
30702  elist[index++] = pointmark(torg) - shift;
30703  elist[index++] = pointmark(tdest) - shift;
30704  elist[index++] = pointmark(tapex) - shift;
30705  if (b->order == 2) { // -o2
30706  out->o2facelist[o2index++] = pointmark(pp[0]) - shift;
30707  out->o2facelist[o2index++] = pointmark(pp[1]) - shift;
30708  out->o2facelist[o2index++] = pointmark(pp[2]) - shift;
30709  }
30710  if (!b->nobound) {
30711  emlist[index1++] = marker;
30712  }
30713  if (b->neighout > 1) {
30714  out->face2tetlist[index2++] = neigh1;
30715  out->face2tetlist[index2++] = neigh2;
30716  }
30717  }
30718  facenumber++;
30719  faceloop.sh = shellfacetraverse(subfaces);
30720  }
30721 
30722  if (out == (tetgenio *) NULL) {
30723  fprintf(outfile, "# Generated by %s\n", b->commandline);
30724  fclose(outfile);
30725  }
30726 }
30727 
30729 // //
30730 // outedges() Output all edges to a .edge file or a tetgenio object. //
30731 // //
30732 // Note: This routine must be called after outelements(), so that the total //
30733 // number of edges 'meshedges' has been counted. //
30734 // //
30736 
30737 void tetgenmesh::outedges(tetgenio* out)
30738 {
30739  FILE *outfile = NULL;
30740  char edgefilename[FILENAMESIZE];
30741  triface tetloop, worktet, spintet;
30742  face checkseg;
30743  point torg, tdest;
30744  int ishulledge;
30745  int firstindex, shift;
30746  int edgenumber, marker;
30747  int index = 0, index1 = 0, index2 = 0;
30748  int t1ver;
30749  int i;
30750 
30751  // For -o2 option.
30752  point *extralist, pp = NULL;
30753  int highorderindex = 11;
30754  int o2index = 0;
30755 
30756  // For -nn option.
30757  int *tet2edgelist = NULL;
30758  int tidx;
30759 
30760  if (out == (tetgenio *) NULL) {
30761  strcpy(edgefilename, b->outfilename);
30762  strcat(edgefilename, ".edge");
30763  }
30764 
30765  if (!b->quiet) {
30766  if (out == (tetgenio *) NULL) {
30767  printf("Writing %s.\n", edgefilename);
30768  } else {
30769  printf("Writing edges.\n");
30770  }
30771  }
30772 
30773  if (meshedges == 0l) {
30774  if (nonconvex) {
30775  numberedges(); // Count the edges.
30776  } else {
30777  // Use Euler's characteristic to get the numbe of edges.
30778  // It states V - E + F - C = 1, hence E = V + F - C - 1.
30779  long tsize = tetrahedrons->items - hullsize;
30780  long fsize = (tsize * 4l + hullsize) / 2l;
30781  long vsize = points->items - dupverts - unuverts;
30782  if (b->weighted) vsize -= nonregularcount;
30783  meshedges = vsize + fsize - tsize - 1;
30784  }
30785  }
30786  meshhulledges = 0l; // It will be counted.
30787 
30788  if (out == (tetgenio *) NULL) {
30789  outfile = fopen(edgefilename, "w");
30790  if (outfile == (FILE *) NULL) {
30791  printf("File I/O Error: Cannot create file %s.\n", edgefilename);
30792  terminatetetgen(this, 1);
30793  }
30794  // Write the number of edges, boundary markers (0 or 1).
30795  fprintf(outfile, "%ld %d\n", meshedges, !b->nobound);
30796  } else {
30797  // Allocate memory for 'edgelist'.
30798  out->numberofedges = meshedges;
30799  out->edgelist = new int[meshedges * 2];
30800  if (out->edgelist == (int *) NULL) {
30801  printf("Error: Out of memory.\n");
30802  terminatetetgen(this, 1);
30803  }
30804  if (b->order == 2) { // -o2 switch
30805  out->o2edgelist = new int[meshedges];
30806  }
30807  if (!b->nobound) {
30808  out->edgemarkerlist = new int[meshedges];
30809  }
30810  if (b->neighout > 1) { // '-nn' switch.
30811  out->edge2tetlist = new int[meshedges];
30812  }
30813  }
30814 
30815  if (b->neighout > 1) { // -nn option
30816  // Output the tetrahedron-to-edge map.
30817  long tsize = tetrahedrons->items - hullsize;
30818  tet2edgelist = new int[tsize * 6];
30819  }
30820 
30821  // Determine the first index (0 or 1).
30822  firstindex = b->zeroindex ? 0 : in->firstnumber;
30823  shift = 0; // Default no shiftment.
30824  if ((in->firstnumber == 1) && (firstindex == 0)) {
30825  shift = 1; // Shift (reduce) the output indices by 1.
30826  }
30827 
30828  tetrahedrons->traversalinit();
30829  tetloop.tet = tetrahedrontraverse();
30830  edgenumber = firstindex; // in->firstnumber;
30831  while (tetloop.tet != (tetrahedron *) NULL) {
30832  // Count the number of Voronoi faces.
30833  worktet.tet = tetloop.tet;
30834  for (i = 0; i < 6; i++) {
30835  worktet.ver = edge2ver[i];
30836  ishulledge = 0;
30837  fnext(worktet, spintet);
30838  do {
30839  if (!ishulltet(spintet)) {
30840  if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
30841  } else {
30842  ishulledge = 1;
30843  }
30844  fnextself(spintet);
30845  } while (spintet.tet != worktet.tet);
30846  if (spintet.tet == worktet.tet) {
30847  // Found a new edge.
30848  if (ishulledge) meshhulledges++;
30849  torg = org(worktet);
30850  tdest = dest(worktet);
30851  if (b->order == 2) { // -o2
30852  // Get the extra vertex on this edge.
30853  extralist = (point *) worktet.tet[highorderindex];
30854  pp = extralist[ver2edge[worktet.ver]];
30855  }
30856  if (out == (tetgenio *) NULL) {
30857  fprintf(outfile, "%5d %4d %4d", edgenumber,
30858  pointmark(torg) - shift, pointmark(tdest) - shift);
30859  if (b->order == 2) { // -o2
30860  fprintf(outfile, " %4d", pointmark(pp) - shift);
30861  }
30862  } else {
30863  // Output three vertices of this face;
30864  out->edgelist[index++] = pointmark(torg) - shift;
30865  out->edgelist[index++] = pointmark(tdest) - shift;
30866  if (b->order == 2) { // -o2
30867  out->o2edgelist[o2index++] = pointmark(pp) - shift;
30868  }
30869  }
30870  if (!b->nobound) {
30871  if (b->plc || b->refine) {
30872  // Check if the edge is a segment.
30873  tsspivot1(worktet, checkseg);
30874  if (checkseg.sh != NULL) {
30875  marker = shellmark(checkseg);
30876  } else {
30877  marker = 0; // It's not a segment.
30878  }
30879  } else {
30880  // Mark it if it is a hull edge.
30881  marker = ishulledge ? 1 : 0;
30882  }
30883  if (out == (tetgenio *) NULL) {
30884  fprintf(outfile, " %d", marker);
30885  } else {
30886  out->edgemarkerlist[index1++] = marker;
30887  }
30888  }
30889  if (b->neighout > 1) { // '-nn' switch.
30890  if (out == (tetgenio *) NULL) {
30891  fprintf(outfile, " %d", elemindex(tetloop.tet));
30892  } else {
30893  out->edge2tetlist[index2++] = elemindex(tetloop.tet);
30894  }
30895  // Fill the tetrahedron-to-edge map.
30896  spintet = worktet;
30897  while (1) {
30898  if (!ishulltet(spintet)) {
30899  tidx = elemindex(spintet.tet) - firstindex;
30900  tet2edgelist[tidx * 6 + ver2edge[spintet.ver]] = edgenumber;
30901  }
30902  fnextself(spintet);
30903  if (spintet.tet == worktet.tet) break;
30904  }
30905  }
30906  if (out == (tetgenio *) NULL) {
30907  fprintf(outfile, "\n");
30908  }
30909  edgenumber++;
30910  }
30911  }
30912  tetloop.tet = tetrahedrontraverse();
30913  }
30914 
30915  if (out == (tetgenio *) NULL) {
30916  fprintf(outfile, "# Generated by %s\n", b->commandline);
30917  fclose(outfile);
30918  }
30919 
30920  if (b->neighout > 1) { // -nn option
30921  long tsize = tetrahedrons->items - hullsize;
30922 
30923  if (b->facesout) { // -f option
30924  // Build the face-to-edge map (use the tet-to-edge map).
30925  long fsize = (tsize * 4l + hullsize) / 2l;
30926  int *face2edgelist = new int[fsize * 3];
30927 
30928  tetrahedrons->traversalinit();
30929  tetloop.tet = tetrahedrontraverse();
30930  int facenumber = 0; // firstindex; // in->firstnumber;
30931  while (tetloop.tet != (tetrahedron *) NULL) {
30932  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
30933  fsym(tetloop, spintet);
30934  if (ishulltet(spintet) ||
30935  (elemindex(tetloop.tet) < elemindex(spintet.tet))) {
30936  // The three edges of this face are ordered such that the
30937  // first edge is opposite to the first vertex of this face
30938  // that appears in the .face file, and so on.
30939  tidx = elemindex(tetloop.tet) - firstindex;
30940  worktet = tetloop;
30941  for (i = 0; i < 3; i++) {
30942  enextself(worktet); // The edge opposite to vertex i.
30943  int eidx = tet2edgelist[tidx * 6 + ver2edge[worktet.ver]];
30944  face2edgelist[facenumber * 3 + i] = eidx;
30945  }
30946  facenumber++;
30947  }
30948  }
30949  tetloop.tet = tetrahedrontraverse();
30950  }
30951 
30952  // Output the face-to-edge map.
30953  if (out == (tetgenio *) NULL) {
30954  strcpy(edgefilename, b->outfilename);
30955  strcat(edgefilename, ".f2e");
30956  }
30957  if (!b->quiet) {
30958  if (out == (tetgenio *) NULL) {
30959  printf("Writing %s.\n", edgefilename);
30960  } else {
30961  printf("Writing face-to-edge map.\n");
30962  }
30963  }
30964  if (out == (tetgenio *) NULL) {
30965  outfile = fopen(edgefilename, "w");
30966  for (tidx = 0; tidx < fsize; tidx++) { // Re-use `tidx'
30967  i = tidx * 3;
30968  fprintf(outfile, "%4d %d %d %d\n", tidx + in->firstnumber,
30969  face2edgelist[i], face2edgelist[i+1], face2edgelist[i+2]);
30970  }
30971  fclose(outfile);
30972  delete [] face2edgelist;
30973  } else {
30974  // Simply copy the address of the list to the output.
30975  out->face2edgelist = face2edgelist;
30976  }
30977  } // if (b->facesout)
30978 
30979  // Output the tetrahedron-to-edge map.
30980  if (out == (tetgenio *) NULL) {
30981  strcpy(edgefilename, b->outfilename);
30982  strcat(edgefilename, ".t2e");
30983  }
30984  if (!b->quiet) {
30985  if (out == (tetgenio *) NULL) {
30986  printf("Writing %s.\n", edgefilename);
30987  } else {
30988  printf("Writing tetrahedron-to-edge map.\n");
30989  }
30990  }
30991  if (out == (tetgenio *) NULL) {
30992  outfile = fopen(edgefilename, "w");
30993  for (tidx = 0; tidx < tsize; tidx++) {
30994  i = tidx * 6;
30995  fprintf(outfile, "%4d %d %d %d %d %d %d\n", tidx + in->firstnumber,
30996  tet2edgelist[i], tet2edgelist[i+1], tet2edgelist[i+2],
30997  tet2edgelist[i+3], tet2edgelist[i+4], tet2edgelist[i+5]);
30998  }
30999  fclose(outfile);
31000  delete [] tet2edgelist;
31001  } else {
31002  // Simply copy the address of the list to the output.
31003  out->tet2edgelist = tet2edgelist;
31004  }
31005  }
31006 }
31007 
31009 // //
31010 // outsubsegments() Output segments to a .edge file or a structure. //
31011 // //
31013 
31014 void tetgenmesh::outsubsegments(tetgenio* out)
31015 {
31016  FILE *outfile = NULL;
31017  char edgefilename[FILENAMESIZE];
31018  int *elist = NULL;
31019  int index, i;
31020  face edgeloop;
31021  point torg, tdest;
31022  int firstindex, shift;
31023  int marker;
31024  int edgenumber;
31025 
31026  // For -o2 option.
31027  triface workface, spintet;
31028  point *extralist, pp = NULL;
31029  int highorderindex = 11;
31030  int o2index = 0;
31031 
31032  // For -nn option.
31033  int neigh = -1;
31034  int index2 = 0;
31035 
31036  int t1ver; // used by fsymself()
31037 
31038  if (out == (tetgenio *) NULL) {
31039  strcpy(edgefilename, b->outfilename);
31040  strcat(edgefilename, ".edge");
31041  }
31042 
31043  if (!b->quiet) {
31044  if (out == (tetgenio *) NULL) {
31045  printf("Writing %s.\n", edgefilename);
31046  } else {
31047  printf("Writing edges.\n");
31048  }
31049  }
31050 
31051  if (out == (tetgenio *) NULL) {
31052  outfile = fopen(edgefilename, "w");
31053  if (outfile == (FILE *) NULL) {
31054  printf("File I/O Error: Cannot create file %s.\n", edgefilename);
31055  terminatetetgen(this, 3);
31056  }
31057  // Number of subsegments.
31058  fprintf(outfile, "%ld 1\n", subsegs->items);
31059  } else {
31060  // Allocate memory for 'edgelist'.
31061  out->edgelist = new int[subsegs->items * (b->order == 1 ? 2 : 3)];
31062  if (out->edgelist == (int *) NULL) {
31063  terminatetetgen(this, 1);
31064  }
31065  if (b->order == 2) {
31066  out->o2edgelist = new int[subsegs->items];
31067  }
31068  out->edgemarkerlist = new int[subsegs->items];
31069  if (out->edgemarkerlist == (int *) NULL) {
31070  terminatetetgen(this, 1);
31071  }
31072  if (b->neighout > 1) {
31073  out->edge2tetlist = new int[subsegs->items];
31074  }
31075  out->numberofedges = subsegs->items;
31076  elist = out->edgelist;
31077  }
31078 
31079  // Determine the first index (0 or 1).
31080  firstindex = b->zeroindex ? 0 : in->firstnumber;
31081  shift = 0; // Default no shiftment.
31082  if ((in->firstnumber == 1) && (firstindex == 0)) {
31083  shift = 1; // Shift the output indices by 1.
31084  }
31085  index = 0;
31086  i = 0;
31087 
31088  subsegs->traversalinit();
31089  edgeloop.sh = shellfacetraverse(subsegs);
31090  edgenumber = firstindex; // in->firstnumber;
31091  while (edgeloop.sh != (shellface *) NULL) {
31092  torg = sorg(edgeloop);
31093  tdest = sdest(edgeloop);
31094  if ((b->order == 2) || (b->neighout > 1)) {
31095  sstpivot1(edgeloop, workface);
31096  if (workface.tet != NULL) {
31097  // We must find a non-hull tet.
31098  if (ishulltet(workface)) {
31099  spintet = workface;
31100  while (1) {
31101  fnextself(spintet);
31102  if (!ishulltet(spintet)) break;
31103  if (spintet.tet == workface.tet) break;
31104  }
31105  workface = spintet;
31106  }
31107  }
31108  }
31109  if (b->order == 2) { // -o2
31110  // Get the extra vertex on this edge.
31111  if (workface.tet != NULL) {
31112  extralist = (point *) workface.tet[highorderindex];
31113  pp = extralist[ver2edge[workface.ver]];
31114  } else {
31115  pp = torg; // There is no extra node available.
31116  }
31117  }
31118  if (b->neighout > 1) { // -nn
31119  if (workface.tet != NULL) {
31120  neigh = elemindex(workface.tet);
31121  } else {
31122  neigh = -1;
31123  }
31124  }
31125  marker = shellmark(edgeloop);
31126  if (marker == 0) {
31127  marker = 1; // Default marker of a boundary edge is 1.
31128  }
31129  if (out == (tetgenio *) NULL) {
31130  fprintf(outfile, "%5d %4d %4d", edgenumber,
31131  pointmark(torg) - shift, pointmark(tdest) - shift);
31132  if (b->order == 2) { // -o2
31133  fprintf(outfile, " %4d", pointmark(pp) - shift);
31134  }
31135  fprintf(outfile, " %d", marker);
31136  if (b->neighout > 1) { // -nn
31137  fprintf(outfile, " %4d", neigh);
31138  }
31139  fprintf(outfile, "\n");
31140  } else {
31141  // Output three vertices of this face;
31142  elist[index++] = pointmark(torg) - shift;
31143  elist[index++] = pointmark(tdest) - shift;
31144  if (b->order == 2) { // -o2
31145  out->o2edgelist[o2index++] = pointmark(pp) - shift;
31146  }
31147  out->edgemarkerlist[i++] = marker;
31148  if (b->neighout > 1) { // -nn
31149  out->edge2tetlist[index2++] = neigh;
31150  }
31151  }
31152  edgenumber++;
31153  edgeloop.sh = shellfacetraverse(subsegs);
31154  }
31155 
31156  if (out == (tetgenio *) NULL) {
31157  fprintf(outfile, "# Generated by %s\n", b->commandline);
31158  fclose(outfile);
31159  }
31160 }
31161 
31163 // //
31164 // outneighbors() Output tet neighbors to a .neigh file or a structure. //
31165 // //
31167 
31168 void tetgenmesh::outneighbors(tetgenio* out)
31169 {
31170  FILE *outfile = NULL;
31171  char neighborfilename[FILENAMESIZE];
31172  int *nlist = NULL;
31173  int index = 0;
31174  triface tetloop, tetsym;
31175  int neighbori[4];
31176  int firstindex;
31177  int elementnumber;
31178  long ntets;
31179 
31180  if (out == (tetgenio *) NULL) {
31181  strcpy(neighborfilename, b->outfilename);
31182  strcat(neighborfilename, ".neigh");
31183  }
31184 
31185  if (!b->quiet) {
31186  if (out == (tetgenio *) NULL) {
31187  printf("Writing %s.\n", neighborfilename);
31188  } else {
31189  printf("Writing neighbors.\n");
31190  }
31191  }
31192 
31193  ntets = tetrahedrons->items - hullsize;
31194 
31195  if (out == (tetgenio *) NULL) {
31196  outfile = fopen(neighborfilename, "w");
31197  if (outfile == (FILE *) NULL) {
31198  printf("File I/O Error: Cannot create file %s.\n", neighborfilename);
31199  terminatetetgen(this, 1);
31200  }
31201  // Number of tetrahedra, four faces per tetrahedron.
31202  fprintf(outfile, "%ld %d\n", ntets, 4);
31203  } else {
31204  // Allocate memory for 'neighborlist'.
31205  out->neighborlist = new int[ntets * 4];
31206  if (out->neighborlist == (int *) NULL) {
31207  printf("Error: Out of memory.\n");
31208  terminatetetgen(this, 1);
31209  }
31210  nlist = out->neighborlist;
31211  }
31212 
31213  // Determine the first index (0 or 1).
31214  firstindex = b->zeroindex ? 0 : in->firstnumber;
31215 
31216  tetrahedrons->traversalinit();
31217  tetloop.tet = tetrahedrontraverse();
31218  elementnumber = firstindex; // in->firstnumber;
31219  while (tetloop.tet != (tetrahedron *) NULL) {
31220  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
31221  fsym(tetloop, tetsym);
31222  if (!ishulltet(tetsym)) {
31223  neighbori[tetloop.ver] = elemindex(tetsym.tet);
31224  } else {
31225  neighbori[tetloop.ver] = -1;
31226  }
31227  }
31228  if (out == (tetgenio *) NULL) {
31229  // Tetrahedra number, neighboring tetrahedron numbers.
31230  fprintf(outfile, "%4d %4d %4d %4d %4d\n", elementnumber,
31231  neighbori[0], neighbori[1], neighbori[2], neighbori[3]);
31232  } else {
31233  nlist[index++] = neighbori[0];
31234  nlist[index++] = neighbori[1];
31235  nlist[index++] = neighbori[2];
31236  nlist[index++] = neighbori[3];
31237  }
31238  tetloop.tet = tetrahedrontraverse();
31239  elementnumber++;
31240  }
31241 
31242  if (out == (tetgenio *) NULL) {
31243  fprintf(outfile, "# Generated by %s\n", b->commandline);
31244  fclose(outfile);
31245  }
31246 }
31247 
31249 // //
31250 // outvoronoi() Output the Voronoi diagram to .v.node, .v.edge, v.face, //
31251 // and .v.cell. //
31252 // //
31253 // The Voronoi diagram is the geometric dual of the Delaunay triangulation. //
31254 // The Voronoi vertices are the circumcenters of Delaunay tetrahedra. Each //
31255 // Voronoi edge connects two Voronoi vertices at two sides of a common Dela- //
31256 // unay face. At a face of convex hull, it becomes a ray (goto the infinity).//
31257 // A Voronoi face is the convex hull of all Voronoi vertices around a common //
31258 // Delaunay edge. It is a closed polygon for any internal Delaunay edge. At a//
31259 // ridge, it is unbounded. Each Voronoi cell is the convex hull of all Vor- //
31260 // onoi vertices around a common Delaunay vertex. It is a polytope for any //
31261 // internal Delaunay vertex. It is an unbounded polyhedron for a Delaunay //
31262 // vertex belonging to the convex hull. //
31263 // //
31264 // NOTE: This routine is only used when the input is only a set of point. //
31265 // Comment: Special thanks to Victor Liu for finding and fixing few bugs. //
31266 // //
31268 
31269 void tetgenmesh::outvoronoi(tetgenio* out)
31270 {
31271  FILE *outfile = NULL;
31272  char outfilename[FILENAMESIZE];
31273  tetgenio::voroedge *vedge = NULL;
31274  tetgenio::vorofacet *vfacet = NULL;
31275  arraypool *tetlist, *ptlist;
31276  triface tetloop, worktet, spintet, firsttet;
31277  point pt[4], ploop, neipt;
31278  REAL ccent[3], infvec[3], vec1[3], vec2[3], L;
31279  long ntets, faces, edges;
31280  int *indexarray, *fidxs, *eidxs;
31281  int arraysize, *vertarray = NULL;
31282  int vpointcount, vedgecount, vfacecount, tcount;
31283  int ishullvert, ishullface;
31284  int index, shift, end1, end2;
31285  int i, j;
31286 
31287  int t1ver; // used by fsymself()
31288 
31289  // Output Voronoi vertices to .v.node file.
31290  if (out == (tetgenio *) NULL) {
31291  strcpy(outfilename, b->outfilename);
31292  strcat(outfilename, ".v.node");
31293  }
31294 
31295  if (!b->quiet) {
31296  if (out == (tetgenio *) NULL) {
31297  printf("Writing %s.\n", outfilename);
31298  } else {
31299  printf("Writing Voronoi vertices.\n");
31300  }
31301  }
31302 
31303  // Determine the first index (0 or 1).
31304  shift = (b->zeroindex ? 0 : in->firstnumber);
31305 
31306  // Each face and edge of the tetrahedral mesh will be indexed for indexing
31307  // the Voronoi edges and facets. Indices of faces and edges are saved in
31308  // each tetrahedron (including hull tets).
31309 
31310  // Allocate the total space once.
31311  indexarray = new int[tetrahedrons->items * 10];
31312 
31313  // Allocate space (10 integers) into each tetrahedron. It re-uses the slot
31314  // for element markers, flags.
31315  i = 0;
31316  tetrahedrons->traversalinit();
31317  tetloop.tet = alltetrahedrontraverse();
31318  while (tetloop.tet != NULL) {
31319  tetloop.tet[11] = (tetrahedron) &(indexarray[i * 10]);
31320  i++;
31321  tetloop.tet = alltetrahedrontraverse();
31322  }
31323 
31324  // The number of tetrahedra (excluding hull tets) (Voronoi vertices).
31325  ntets = tetrahedrons->items - hullsize;
31326  // The number of Delaunay faces (Voronoi edges).
31327  faces = (4l * ntets + hullsize) / 2l;
31328  // The number of Delaunay edges (Voronoi faces).
31329  long vsize = points->items - dupverts - unuverts;
31330  if (b->weighted) vsize -= nonregularcount;
31331  if (!nonconvex) {
31332  edges = vsize + faces - ntets - 1;
31333  } else {
31334  if (meshedges == 0l) {
31335  numberedges(); // Count edges.
31336  }
31337  edges = meshedges;
31338  }
31339 
31340  if (out == (tetgenio *) NULL) {
31341  outfile = fopen(outfilename, "w");
31342  if (outfile == (FILE *) NULL) {
31343  printf("File I/O Error: Cannot create file %s.\n", outfilename);
31344  terminatetetgen(this, 3);
31345  }
31346  // Number of voronoi points, 3 dim, no attributes, no marker.
31347  fprintf(outfile, "%ld 3 0 0\n", ntets);
31348  } else {
31349  // Allocate space for 'vpointlist'.
31350  out->numberofvpoints = (int) ntets;
31351  out->vpointlist = new REAL[out->numberofvpoints * 3];
31352  if (out->vpointlist == (REAL *) NULL) {
31353  terminatetetgen(this, 1);
31354  }
31355  }
31356 
31357  // Output Voronoi vertices (the circumcenters of tetrahedra).
31358  tetrahedrons->traversalinit();
31359  tetloop.tet = tetrahedrontraverse();
31360  vpointcount = 0; // The (internal) v-index always starts from 0.
31361  index = 0;
31362  while (tetloop.tet != (tetrahedron *) NULL) {
31363  for (i = 0; i < 4; i++) {
31364  pt[i] = (point) tetloop.tet[4 + i];
31365  setpoint2tet(pt[i], encode(tetloop));
31366  }
31367  if (b->weighted) {
31368  orthosphere(pt[0], pt[1], pt[2], pt[3], pt[0][3], pt[1][3], pt[2][3],
31369  pt[3][3], ccent, NULL);
31370  } else {
31371  circumsphere(pt[0], pt[1], pt[2], pt[3], ccent, NULL);
31372  }
31373  if (out == (tetgenio *) NULL) {
31374  fprintf(outfile, "%4d %16.8e %16.8e %16.8e\n", vpointcount + shift,
31375  ccent[0], ccent[1], ccent[2]);
31376  } else {
31377  out->vpointlist[index++] = ccent[0];
31378  out->vpointlist[index++] = ccent[1];
31379  out->vpointlist[index++] = ccent[2];
31380  }
31381  setelemindex(tetloop.tet, vpointcount);
31382  vpointcount++;
31383  tetloop.tet = tetrahedrontraverse();
31384  }
31385 
31386  if (out == (tetgenio *) NULL) {
31387  fprintf(outfile, "# Generated by %s\n", b->commandline);
31388  fclose(outfile);
31389  }
31390 
31391  // Output Voronoi edges to .v.edge file.
31392  if (out == (tetgenio *) NULL) {
31393  strcpy(outfilename, b->outfilename);
31394  strcat(outfilename, ".v.edge");
31395  }
31396 
31397  if (!b->quiet) {
31398  if (out == (tetgenio *) NULL) {
31399  printf("Writing %s.\n", outfilename);
31400  } else {
31401  printf("Writing Voronoi edges.\n");
31402  }
31403  }
31404 
31405  if (out == (tetgenio *) NULL) {
31406  outfile = fopen(outfilename, "w");
31407  if (outfile == (FILE *) NULL) {
31408  printf("File I/O Error: Cannot create file %s.\n", outfilename);
31409  terminatetetgen(this, 3);
31410  }
31411  // Number of Voronoi edges, no marker.
31412  fprintf(outfile, "%ld 0\n", faces);
31413  } else {
31414  // Allocate space for 'vpointlist'.
31415  out->numberofvedges = (int) faces;
31416  out->vedgelist = new tetgenio::voroedge[out->numberofvedges];
31417  }
31418 
31419  // Output the Voronoi edges.
31420  tetrahedrons->traversalinit();
31421  tetloop.tet = tetrahedrontraverse();
31422  vedgecount = 0; // D-Face (V-edge) index (from zero).
31423  index = 0; // The Delaunay-face index.
31424  while (tetloop.tet != (tetrahedron *) NULL) {
31425  // Count the number of Voronoi edges. Look at the four faces of each
31426  // tetrahedron. Count the face if the tetrahedron's index is
31427  // smaller than its neighbor's or the neighbor is outside.
31428  end1 = elemindex(tetloop.tet);
31429  for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) {
31430  fsym(tetloop, worktet);
31431  if (ishulltet(worktet) ||
31432  (elemindex(tetloop.tet) < elemindex(worktet.tet))) {
31433  // Found a Voronoi edge. Operate on it.
31434  if (out == (tetgenio *) NULL) {
31435  fprintf(outfile, "%4d %4d", vedgecount + shift, end1 + shift);
31436  } else {
31437  vedge = &(out->vedgelist[index++]);
31438  vedge->v1 = end1 + shift;
31439  }
31440  if (!ishulltet(worktet)) {
31441  end2 = elemindex(worktet.tet);
31442  } else {
31443  end2 = -1;
31444  }
31445  // Note that end2 may be -1 (worktet.tet is outside).
31446  if (end2 == -1) {
31447  // Calculate the out normal of this hull face.
31448  pt[0] = dest(worktet);
31449  pt[1] = org(worktet);
31450  pt[2] = apex(worktet);
31451  for (j = 0; j < 3; j++) vec1[j] = pt[1][j] - pt[0][j];
31452  for (j = 0; j < 3; j++) vec2[j] = pt[2][j] - pt[0][j];
31453  cross(vec1, vec2, infvec);
31454  // Normalize it.
31455  L = sqrt(infvec[0] * infvec[0] + infvec[1] * infvec[1]
31456  + infvec[2] * infvec[2]);
31457  if (L > 0) for (j = 0; j < 3; j++) infvec[j] /= L;
31458  if (out == (tetgenio *) NULL) {
31459  fprintf(outfile, " -1");
31460  fprintf(outfile, " %g %g %g\n", infvec[0], infvec[1], infvec[2]);
31461  } else {
31462  vedge->v2 = -1;
31463  vedge->vnormal[0] = infvec[0];
31464  vedge->vnormal[1] = infvec[1];
31465  vedge->vnormal[2] = infvec[2];
31466  }
31467  } else {
31468  if (out == (tetgenio *) NULL) {
31469  fprintf(outfile, " %4d\n", end2 + shift);
31470  } else {
31471  vedge->v2 = end2 + shift;
31472  vedge->vnormal[0] = 0.0;
31473  vedge->vnormal[1] = 0.0;
31474  vedge->vnormal[2] = 0.0;
31475  }
31476  }
31477  // Save the V-edge index in this tet and its neighbor.
31478  fidxs = (int *) (tetloop.tet[11]);
31479  fidxs[tetloop.ver] = vedgecount;
31480  fidxs = (int *) (worktet.tet[11]);
31481  fidxs[worktet.ver & 3] = vedgecount;
31482  vedgecount++;
31483  }
31484  } // tetloop.ver
31485  tetloop.tet = tetrahedrontraverse();
31486  }
31487 
31488  if (out == (tetgenio *) NULL) {
31489  fprintf(outfile, "# Generated by %s\n", b->commandline);
31490  fclose(outfile);
31491  }
31492 
31493  // Output Voronoi faces to .v.face file.
31494  if (out == (tetgenio *) NULL) {
31495  strcpy(outfilename, b->outfilename);
31496  strcat(outfilename, ".v.face");
31497  }
31498 
31499  if (!b->quiet) {
31500  if (out == (tetgenio *) NULL) {
31501  printf("Writing %s.\n", outfilename);
31502  } else {
31503  printf("Writing Voronoi faces.\n");
31504  }
31505  }
31506 
31507  if (out == (tetgenio *) NULL) {
31508  outfile = fopen(outfilename, "w");
31509  if (outfile == (FILE *) NULL) {
31510  printf("File I/O Error: Cannot create file %s.\n", outfilename);
31511  terminatetetgen(this, 3);
31512  }
31513  // Number of Voronoi faces.
31514  fprintf(outfile, "%ld 0\n", edges);
31515  } else {
31516  out->numberofvfacets = edges;
31517  out->vfacetlist = new tetgenio::vorofacet[out->numberofvfacets];
31518  if (out->vfacetlist == (tetgenio::vorofacet *) NULL) {
31519  terminatetetgen(this, 1);
31520  }
31521  }
31522 
31523  // Output the Voronoi facets.
31524  tetrahedrons->traversalinit();
31525  tetloop.tet = tetrahedrontraverse();
31526  vfacecount = 0; // D-edge (V-facet) index (from zero).
31527  while (tetloop.tet != (tetrahedron *) NULL) {
31528  // Count the number of Voronoi faces. Look at the six edges of each
31529  // tetrahedron. Count the edge only if the tetrahedron's index is
31530  // smaller than those of all other tetrahedra that share the edge.
31531  worktet.tet = tetloop.tet;
31532  for (i = 0; i < 6; i++) {
31533  worktet.ver = edge2ver[i];
31534  // Count the number of faces at this edge. If the edge is a hull edge,
31535  // the face containing dummypoint is also counted.
31536  //ishulledge = 0; // Is it a hull edge.
31537  tcount = 0;
31538  firsttet = worktet;
31539  spintet = worktet;
31540  while (1) {
31541  tcount++;
31542  fnextself(spintet);
31543  if (spintet.tet == worktet.tet) break;
31544  if (!ishulltet(spintet)) {
31545  if (elemindex(spintet.tet) < elemindex(worktet.tet)) break;
31546  } else {
31547  //ishulledge = 1;
31548  if (apex(spintet) == dummypoint) {
31549  // We make this V-edge appear in the end of the edge list.
31550  fnext(spintet, firsttet);
31551  }
31552  }
31553  } // while (1)
31554  if (spintet.tet == worktet.tet) {
31555  // Found a Voronoi facet. Operate on it.
31556  pt[0] = org(worktet);
31557  pt[1] = dest(worktet);
31558  end1 = pointmark(pt[0]) - in->firstnumber; // V-cell index
31559  end2 = pointmark(pt[1]) - in->firstnumber;
31560  if (out == (tetgenio *) NULL) {
31561  fprintf(outfile, "%4d %4d %4d %-2d ", vfacecount + shift,
31562  end1 + shift, end2 + shift, tcount);
31563  } else {
31564  vfacet = &(out->vfacetlist[vfacecount]);
31565  vfacet->c1 = end1 + shift;
31566  vfacet->c2 = end2 + shift;
31567  vfacet->elist = new int[tcount + 1];
31568  vfacet->elist[0] = tcount;
31569  index = 1;
31570  }
31571  // Output V-edges of this V-facet.
31572  spintet = firsttet; //worktet;
31573  while (1) {
31574  fidxs = (int *) (spintet.tet[11]);
31575  if (apex(spintet) != dummypoint) {
31576  vedgecount = fidxs[spintet.ver & 3];
31577  ishullface = 0;
31578  } else {
31579  ishullface = 1; // It's not a real face.
31580  }
31581  if (out == (tetgenio *) NULL) {
31582  fprintf(outfile, " %d", !ishullface ? (vedgecount + shift) : -1);
31583  } else {
31584  vfacet->elist[index++] = !ishullface ? (vedgecount + shift) : -1;
31585  }
31586  // Save the V-facet index in this tet at this edge.
31587  eidxs = &(fidxs[4]);
31588  eidxs[ver2edge[spintet.ver]] = vfacecount;
31589  // Go to the next face.
31590  fnextself(spintet);
31591  if (spintet.tet == firsttet.tet) break;
31592  } // while (1)
31593  if (out == (tetgenio *) NULL) {
31594  fprintf(outfile, "\n");
31595  }
31596  vfacecount++;
31597  } // if (spintet.tet == worktet.tet)
31598  } // if (i = 0; i < 6; i++)
31599  tetloop.tet = tetrahedrontraverse();
31600  }
31601 
31602  if (out == (tetgenio *) NULL) {
31603  fprintf(outfile, "# Generated by %s\n", b->commandline);
31604  fclose(outfile);
31605  }
31606 
31607  // Output Voronoi cells to .v.cell file.
31608  if (out == (tetgenio *) NULL) {
31609  strcpy(outfilename, b->outfilename);
31610  strcat(outfilename, ".v.cell");
31611  }
31612 
31613  if (!b->quiet) {
31614  if (out == (tetgenio *) NULL) {
31615  printf("Writing %s.\n", outfilename);
31616  } else {
31617  printf("Writing Voronoi cells.\n");
31618  }
31619  }
31620 
31621  if (out == (tetgenio *) NULL) {
31622  outfile = fopen(outfilename, "w");
31623  if (outfile == (FILE *) NULL) {
31624  printf("File I/O Error: Cannot create file %s.\n", outfilename);
31625  terminatetetgen(this, 3);
31626  }
31627  // Number of Voronoi cells.
31628  fprintf(outfile, "%ld\n", points->items - unuverts - dupverts);
31629  } else {
31630  out->numberofvcells = points->items - unuverts - dupverts;
31631  out->vcelllist = new int*[out->numberofvcells];
31632  if (out->vcelllist == (int **) NULL) {
31633  terminatetetgen(this, 1);
31634  }
31635  }
31636 
31637  // Output Voronoi cells.
31638  tetlist = cavetetlist;
31639  ptlist = cavetetvertlist;
31640  points->traversalinit();
31641  ploop = pointtraverse();
31642  vpointcount = 0;
31643  while (ploop != (point) NULL) {
31644  if ((pointtype(ploop) != UNUSEDVERTEX) &&
31645  (pointtype(ploop) != DUPLICATEDVERTEX) &&
31646  (pointtype(ploop) != NREGULARVERTEX)) {
31647  getvertexstar(1, ploop, tetlist, ptlist, NULL);
31648  // Mark all vertices. Check if it is a hull vertex.
31649  ishullvert = 0;
31650  for (i = 0; i < ptlist->objects; i++) {
31651  neipt = * (point *) fastlookup(ptlist, i);
31652  if (neipt != dummypoint) {
31653  pinfect(neipt);
31654  } else {
31655  ishullvert = 1;
31656  }
31657  }
31658  tcount = (int) ptlist->objects;
31659  if (out == (tetgenio *) NULL) {
31660  fprintf(outfile, "%4d %-2d ", vpointcount + shift, tcount);
31661  } else {
31662  arraysize = tcount;
31663  vertarray = new int[arraysize + 1];
31664  out->vcelllist[vpointcount] = vertarray;
31665  vertarray[0] = tcount;
31666  index = 1;
31667  }
31668  // List Voronoi facets bounding this cell.
31669  for (i = 0; i < tetlist->objects; i++) {
31670  worktet = * (triface *) fastlookup(tetlist, i);
31671  // Let 'worktet' be [a,b,c,d] where d = ploop.
31672  for (j = 0; j < 3; j++) {
31673  neipt = org(worktet); // neipt is a, or b, or c
31674  // Skip the dummypoint.
31675  if (neipt != dummypoint) {
31676  if (pinfected(neipt)) {
31677  // It's not processed yet.
31678  puninfect(neipt);
31679  // Go to the DT edge [a,d], or [b,d], or [c,d].
31680  esym(worktet, spintet);
31681  enextself(spintet);
31682  // Get the V-face dual to this edge.
31683  eidxs = (int *) spintet.tet[11];
31684  vfacecount = eidxs[4 + ver2edge[spintet.ver]];
31685  if (out == (tetgenio *) NULL) {
31686  fprintf(outfile, " %d", vfacecount + shift);
31687  } else {
31688  vertarray[index++] = vfacecount + shift;
31689  }
31690  }
31691  }
31692  enextself(worktet);
31693  } // j
31694  } // i
31695  if (ishullvert) {
31696  // Add a hull facet (-1) to the facet list.
31697  if (out == (tetgenio *) NULL) {
31698  fprintf(outfile, " -1");
31699  } else {
31700  vertarray[index++] = -1;
31701  }
31702  }
31703  if (out == (tetgenio *) NULL) {
31704  fprintf(outfile, "\n");
31705  }
31706  tetlist->restart();
31707  ptlist->restart();
31708  vpointcount++;
31709  }
31710  ploop = pointtraverse();
31711  }
31712 
31713  // Delete the space for face/edge indices.
31714  delete [] indexarray;
31715 
31716  if (out == (tetgenio *) NULL) {
31717  fprintf(outfile, "# Generated by %s\n", b->commandline);
31718  fclose(outfile);
31719  }
31720 }
31721 
31723 // //
31724 // outsmesh() Write surface mesh to a .smesh file, which can be read and //
31725 // tetrahedralized by TetGen. //
31726 // //
31727 // You can specify a filename (without suffix) in 'smfilename'. If you don't //
31728 // supply a filename (let smfilename be NULL), the default name stored in //
31729 // 'tetgenbehavior' will be used. //
31730 // //
31732 
31733 void tetgenmesh::outsmesh(char* smfilename)
31734 {
31735  FILE *outfile;
31736  char nodfilename[FILENAMESIZE];
31737  char smefilename[FILENAMESIZE];
31738  face faceloop;
31739  point p1, p2, p3;
31740  int firstindex, shift;
31741  int bmark;
31742  int marker;
31743  int i;
31744 
31745  if (smfilename != (char *) NULL && smfilename[0] != '\0') {
31746  strcpy(smefilename, smfilename);
31747  } else if (b->outfilename[0] != '\0') {
31748  strcpy(smefilename, b->outfilename);
31749  } else {
31750  strcpy(smefilename, "unnamed");
31751  }
31752  strcpy(nodfilename, smefilename);
31753  strcat(smefilename, ".smesh");
31754  strcat(nodfilename, ".node");
31755 
31756  if (!b->quiet) {
31757  printf("Writing %s.\n", smefilename);
31758  }
31759  outfile = fopen(smefilename, "w");
31760  if (outfile == (FILE *) NULL) {
31761  printf("File I/O Error: Cannot create file %s.\n", smefilename);
31762  return;
31763  }
31764 
31765  // Determine the first index (0 or 1).
31766  firstindex = b->zeroindex ? 0 : in->firstnumber;
31767  shift = 0; // Default no shiftment.
31768  if ((in->firstnumber == 1) && (firstindex == 0)) {
31769  shift = 1; // Shift the output indices by 1.
31770  }
31771 
31772  fprintf(outfile, "# %s. TetGen's input file.\n", smefilename);
31773  fprintf(outfile, "\n# part 1: node list.\n");
31774  fprintf(outfile, "0 3 0 0 # nodes are found in %s.\n", nodfilename);
31775 
31776  marker = 0; // avoid compile warning.
31777  bmark = !b->nobound && (in->facetmarkerlist || in->trifacemarkerlist);
31778 
31779  fprintf(outfile, "\n# part 2: facet list.\n");
31780  // Number of facets, boundary marker.
31781  fprintf(outfile, "%ld %d\n", subfaces->items, bmark);
31782 
31783  subfaces->traversalinit();
31784  faceloop.sh = shellfacetraverse(subfaces);
31785  while (faceloop.sh != (shellface *) NULL) {
31786  p1 = sorg(faceloop);
31787  p2 = sdest(faceloop);
31788  p3 = sapex(faceloop);
31789  if (bmark) {
31790  marker = shellmark(faceloop);
31791  }
31792  fprintf(outfile, "3 %4d %4d %4d", pointmark(p1) - shift,
31793  pointmark(p2) - shift, pointmark(p3) - shift);
31794  if (bmark) {
31795  fprintf(outfile, " %d", marker);
31796  }
31797  fprintf(outfile, "\n");
31798  faceloop.sh = shellfacetraverse(subfaces);
31799  }
31800 
31801  // Copy input holelist.
31802  fprintf(outfile, "\n# part 3: hole list.\n");
31803  fprintf(outfile, "%d\n", in->numberofholes);
31804  for (i = 0; i < in->numberofholes; i++) {
31805  fprintf(outfile, "%d %g %g %g\n", i + in->firstnumber,
31806  in->holelist[i * 3], in->holelist[i * 3 + 1],
31807  in->holelist[i * 3 + 2]);
31808  }
31809 
31810  // Copy input regionlist.
31811  fprintf(outfile, "\n# part 4: region list.\n");
31812  fprintf(outfile, "%d\n", in->numberofregions);
31813  for (i = 0; i < in->numberofregions; i++) {
31814  fprintf(outfile, "%d %g %g %g %d %g\n", i + in->firstnumber,
31815  in->regionlist[i * 5], in->regionlist[i * 5 + 1],
31816  in->regionlist[i * 5 + 2], (int) in->regionlist[i * 5 + 3],
31817  in->regionlist[i * 5 + 4]);
31818  }
31819 
31820  fprintf(outfile, "# Generated by %s\n", b->commandline);
31821  fclose(outfile);
31822 }
31823 
31825 // //
31826 // outmesh2medit() Write mesh to a .mesh file, which can be read and //
31827 // rendered by Medit (a free mesh viewer from INRIA). //
31828 // //
31829 // You can specify a filename (without suffix) in 'mfilename'. If you don't //
31830 // supply a filename (let mfilename be NULL), the default name stored in //
31831 // 'tetgenbehavior' will be used. The output file will have the suffix .mesh.//
31832 // //
31834 
31835 void tetgenmesh::outmesh2medit(char* mfilename)
31836 {
31837  FILE *outfile;
31838  char mefilename[FILENAMESIZE];
31839  tetrahedron* tetptr;
31840  triface tface, tsymface;
31841  face segloop, checkmark;
31842  point ptloop, p1, p2, p3, p4;
31843  long ntets, faces;
31844  int pointnumber;
31845  int marker;
31846  int i;
31847 
31848  if (mfilename != (char *) NULL && mfilename[0] != '\0') {
31849  strcpy(mefilename, mfilename);
31850  } else if (b->outfilename[0] != '\0') {
31851  strcpy(mefilename, b->outfilename);
31852  } else {
31853  strcpy(mefilename, "unnamed");
31854  }
31855  strcat(mefilename, ".mesh");
31856 
31857  if (!b->quiet) {
31858  printf("Writing %s.\n", mefilename);
31859  }
31860  outfile = fopen(mefilename, "w");
31861  if (outfile == (FILE *) NULL) {
31862  printf("File I/O Error: Cannot create file %s.\n", mefilename);
31863  return;
31864  }
31865 
31866  fprintf(outfile, "MeshVersionFormatted 1\n");
31867  fprintf(outfile, "\n");
31868  fprintf(outfile, "Dimension\n");
31869  fprintf(outfile, "3\n");
31870  fprintf(outfile, "\n");
31871 
31872  fprintf(outfile, "\n# Set of mesh vertices\n");
31873  fprintf(outfile, "Vertices\n");
31874  fprintf(outfile, "%ld\n", points->items);
31875 
31876  points->traversalinit();
31877  ptloop = pointtraverse();
31878  pointnumber = 1; // Medit need start number form 1.
31879  while (ptloop != (point) NULL) {
31880  // Point coordinates.
31881  fprintf(outfile, "%.17g %.17g %.17g", ptloop[0], ptloop[1], ptloop[2]);
31882  if (in->numberofpointattributes > 0) {
31883  // Write an attribute, ignore others if more than one.
31884  fprintf(outfile, " %.17g\n", ptloop[3]);
31885  } else {
31886  fprintf(outfile, " 0\n");
31887  }
31888  setpointmark(ptloop, pointnumber);
31889  ptloop = pointtraverse();
31890  pointnumber++;
31891  }
31892 
31893  // Compute the number of faces.
31894  ntets = tetrahedrons->items - hullsize;
31895  faces = (ntets * 4l + hullsize) / 2l;
31896 
31897  fprintf(outfile, "\n# Set of Triangles\n");
31898  fprintf(outfile, "Triangles\n");
31899  fprintf(outfile, "%ld\n", faces);
31900 
31901  tetrahedrons->traversalinit();
31902  tface.tet = tetrahedrontraverse();
31903  while (tface.tet != (tetrahedron *) NULL) {
31904  for (tface.ver = 0; tface.ver < 4; tface.ver ++) {
31905  fsym(tface, tsymface);
31906  if (ishulltet(tsymface) ||
31907  (elemindex(tface.tet) < elemindex(tsymface.tet))) {
31908  p1 = org (tface);
31909  p2 = dest(tface);
31910  p3 = apex(tface);
31911  fprintf(outfile, "%5d %5d %5d",
31912  pointmark(p1), pointmark(p2), pointmark(p3));
31913  // Check if it is a subface.
31914  tspivot(tface, checkmark);
31915  if (checkmark.sh == NULL) {
31916  marker = 0; // It is an inner face. It's marker is 0.
31917  } else {
31918  marker = shellmark(checkmark);
31919  }
31920  fprintf(outfile, " %d\n", marker);
31921  }
31922  }
31923  tface.tet = tetrahedrontraverse();
31924  }
31925 
31926  fprintf(outfile, "\n# Set of Tetrahedra\n");
31927  fprintf(outfile, "Tetrahedra\n");
31928  fprintf(outfile, "%ld\n", ntets);
31929 
31930  tetrahedrons->traversalinit();
31931  tetptr = tetrahedrontraverse();
31932  while (tetptr != (tetrahedron *) NULL) {
31933  if (!b->reversetetori) {
31934  p1 = (point) tetptr[4];
31935  p2 = (point) tetptr[5];
31936  } else {
31937  p1 = (point) tetptr[5];
31938  p2 = (point) tetptr[4];
31939  }
31940  p3 = (point) tetptr[6];
31941  p4 = (point) tetptr[7];
31942  fprintf(outfile, "%5d %5d %5d %5d",
31943  pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4));
31944  if (numelemattrib > 0) {
31945  fprintf(outfile, " %.17g", elemattribute(tetptr, 0));
31946  } else {
31947  fprintf(outfile, " 0");
31948  }
31949  fprintf(outfile, "\n");
31950  tetptr = tetrahedrontraverse();
31951  }
31952 
31953  fprintf(outfile, "\nCorners\n");
31954  fprintf(outfile, "%d\n", in->numberofpoints);
31955 
31956  for (i = 0; i < in->numberofpoints; i++) {
31957  fprintf(outfile, "%4d\n", i + 1);
31958  }
31959 
31960  if (b->plc || b->refine) {
31961  fprintf(outfile, "\nEdges\n");
31962  fprintf(outfile, "%ld\n", subsegs->items);
31963 
31964  subsegs->traversalinit();
31965  segloop.sh = shellfacetraverse(subsegs);
31966  while (segloop.sh != (shellface *) NULL) {
31967  p1 = sorg(segloop);
31968  p2 = sdest(segloop);
31969  fprintf(outfile, "%5d %5d", pointmark(p1), pointmark(p2));
31970  marker = shellmark(segloop);
31971  fprintf(outfile, " %d\n", marker);
31972  segloop.sh = shellfacetraverse(subsegs);
31973  }
31974  }
31975 
31976  fprintf(outfile, "\nEnd\n");
31977  fclose(outfile);
31978 }
31979 
31980 
31981 
31982 
31983 
31985 // //
31986 // outmesh2vtk() Save mesh to file in VTK Legacy format. //
31987 // //
31988 // This function was contributed by Bryn Llyod from ETH, 2007. //
31989 // //
31991 
31992 void tetgenmesh::outmesh2vtk(char* ofilename)
31993 {
31994  FILE *outfile;
31995  char vtkfilename[FILENAMESIZE];
31996  point pointloop, p1, p2, p3, p4;
31997  tetrahedron* tptr;
31998  double x, y, z;
31999  int n1, n2, n3, n4;
32000  int nnodes = 4;
32001  int celltype = 10;
32002 
32003  if (b->order == 2) {
32004  printf(" Write VTK not implemented for order 2 elements \n");
32005  return;
32006  }
32007 
32008  int NEL = tetrahedrons->items - hullsize;
32009  int NN = points->items;
32010 
32011  if (ofilename != (char *) NULL && ofilename[0] != '\0') {
32012  strcpy(vtkfilename, ofilename);
32013  } else if (b->outfilename[0] != '\0') {
32014  strcpy(vtkfilename, b->outfilename);
32015  } else {
32016  strcpy(vtkfilename, "unnamed");
32017  }
32018  strcat(vtkfilename, ".vtk");
32019 
32020  if (!b->quiet) {
32021  printf("Writing %s.\n", vtkfilename);
32022  }
32023  outfile = fopen(vtkfilename, "w");
32024  if (outfile == (FILE *) NULL) {
32025  printf("File I/O Error: Cannot create file %s.\n", vtkfilename);
32026  return;
32027  }
32028 
32029  //always write big endian
32030  //bool ImALittleEndian = !testIsBigEndian();
32031 
32032  fprintf(outfile, "# vtk DataFile Version 2.0\n");
32033  fprintf(outfile, "Unstructured Grid\n");
32034  fprintf(outfile, "ASCII\n"); // BINARY
32035  fprintf(outfile, "DATASET UNSTRUCTURED_GRID\n");
32036  fprintf(outfile, "POINTS %d double\n", NN);
32037 
32038  points->traversalinit();
32039  pointloop = pointtraverse();
32040  for(int id=0; id<NN && pointloop != (point) NULL; id++){
32041  x = pointloop[0];
32042  y = pointloop[1];
32043  z = pointloop[2];
32044  fprintf(outfile, "%.17g %.17g %.17g\n", x, y, z);
32045  pointloop = pointtraverse();
32046  }
32047  fprintf(outfile, "\n");
32048 
32049  fprintf(outfile, "CELLS %d %d\n", NEL, NEL*(4+1));
32050  //NEL rows, each has 1 type id + 4 node id's
32051 
32052  tetrahedrons->traversalinit();
32053  tptr = tetrahedrontraverse();
32054  //elementnumber = firstindex; // in->firstnumber;
32055  while (tptr != (tetrahedron *) NULL) {
32056  if (!b->reversetetori) {
32057  p1 = (point) tptr[4];
32058  p2 = (point) tptr[5];
32059  } else {
32060  p1 = (point) tptr[5];
32061  p2 = (point) tptr[4];
32062  }
32063  p3 = (point) tptr[6];
32064  p4 = (point) tptr[7];
32065  n1 = pointmark(p1) - in->firstnumber;
32066  n2 = pointmark(p2) - in->firstnumber;
32067  n3 = pointmark(p3) - in->firstnumber;
32068  n4 = pointmark(p4) - in->firstnumber;
32069  fprintf(outfile, "%d %4d %4d %4d %4d\n", nnodes, n1, n2, n3, n4);
32070  tptr = tetrahedrontraverse();
32071  }
32072  fprintf(outfile, "\n");
32073 
32074  fprintf(outfile, "CELL_TYPES %d\n", NEL);
32075  for(int tid=0; tid<NEL; tid++){
32076  fprintf(outfile, "%d\n", celltype);
32077  }
32078  fprintf(outfile, "\n");
32079 
32080  if (numelemattrib > 0) {
32081  // Output tetrahedra region attributes.
32082  fprintf(outfile, "CELL_DATA %d\n", NEL);
32083  fprintf(outfile, "SCALARS cell_scalars int 1\n");
32084  fprintf(outfile, "LOOKUP_TABLE default\n");
32085  tetrahedrons->traversalinit();
32086  tptr = tetrahedrontraverse();
32087  while (tptr != (tetrahedron *) NULL) {
32088  fprintf(outfile, "%d\n", (int) elemattribute(tptr, numelemattrib - 1));
32089  tptr = tetrahedrontraverse();
32090  }
32091  fprintf(outfile, "\n");
32092  }
32093 
32094  fclose(outfile);
32095 }
32096 
32100 
32104 
32106 // //
32107 // tetrahedralize() The interface for users using TetGen library to //
32108 // generate tetrahedral meshes with all features. //
32109 // //
32110 // The sequence is roughly as follows. Many of these steps can be skipped, //
32111 // depending on the command line switches. //
32112 // //
32113 // - Initialize constants and parse the command line. //
32114 // - Read the vertices from a file and either //
32115 // - tetrahedralize them (no -r), or //
32116 // - read an old mesh from files and reconstruct it (-r). //
32117 // - Insert the boundary segments and facets (-p or -Y). //
32118 // - Read the holes (-p), regional attributes (-pA), and regional volume //
32119 // constraints (-pa). Carve the holes and concavities, and spread the //
32120 // regional attributes and volume constraints. //
32121 // - Enforce the constraints on minimum quality bound (-q) and maximum //
32122 // volume (-a), and a mesh size function (-m). //
32123 // - Optimize the mesh wrt. specified quality measures (-O and -o). //
32124 // - Write the output files and print the statistics. //
32125 // - Check the consistency of the mesh (-C). //
32126 // //
32128 
32129 tetgenmesh* tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out,
32130  tetgenio *addin, tetgenio *bgmin)
32131 {
32132  tetgenmesh* mptr;
32133  mptr = new tetgenmesh;
32134  tetgenmesh& m = *mptr;
32135  clock_t tv[12], ts[5]; // Timing informations (defined in time.h)
32136  REAL cps = (REAL) CLOCKS_PER_SEC;
32137 
32138  tv[0] = clock();
32139 
32140  m.b = b;
32141  m.in = in;
32142  m.addin = addin;
32143 
32144  if (b->metric && bgmin && (bgmin->numberofpoints > 0)) {
32145  m.bgm = new tetgenmesh(); // Create an empty background mesh.
32146  m.bgm->b = b;
32147  m.bgm->in = bgmin;
32148  }
32149 
32150  m.initializepools();
32151  m.transfernodes();
32152 
32153  exactinit(b->verbose, b->noexact, b->nostaticfilter,
32154  m.xmax - m.xmin, m.ymax - m.ymin, m.zmax - m.zmin);
32155 
32156  tv[1] = clock();
32157 
32158  if (b->refine) { // -r
32159  m.reconstructmesh();
32160  } else { // -p
32161  m.incrementaldelaunay(ts[0]);
32162  }
32163 
32164  tv[2] = clock();
32165 
32166  if (!b->quiet) {
32167  if (b->refine) {
32168  printf("Mesh reconstruction seconds: %g\n", ((REAL)(tv[2]-tv[1])) / cps);
32169  } else {
32170  printf("Delaunay seconds: %g\n", ((REAL)(tv[2]-tv[1])) / cps);
32171  if (b->verbose) {
32172  printf(" Point sorting seconds: %g\n", ((REAL)(ts[0]-tv[1])) / cps);
32173 
32174  }
32175  }
32176  }
32177 
32178  if (b->plc && !b->refine) { // -p
32179  m.meshsurface();
32180 
32181  ts[0] = clock();
32182 
32183  if (!b->quiet) {
32184  printf("Surface mesh seconds: %g\n", ((REAL)(ts[0]-tv[2])) / cps);
32185  }
32186 
32187  if (b->diagnose) { // -d
32188  m.detectinterfaces();
32189 
32190  ts[1] = clock();
32191 
32192  if (!b->quiet) {
32193  printf("Self-intersection seconds: %g\n", ((REAL)(ts[1]-ts[0])) / cps);
32194  }
32195 
32196  // Only output when self-intersecting faces exist.
32197  if (m.subfaces->items > 0l) {
32198  m.outnodes(out);
32199  m.outsubfaces(out);
32200  }
32201 
32202  return mptr;
32203  }
32204  }
32205 
32206 
32207  tv[3] = clock();
32208 
32209  if ((b->metric) && (m.bgm != NULL)) { // -m
32210  m.bgm->initializepools();
32211  m.bgm->transfernodes();
32212  m.bgm->reconstructmesh();
32213 
32214  ts[0] = clock();
32215 
32216  if (!b->quiet) {
32217  printf("Background mesh reconstruct seconds: %g\n",
32218  ((REAL)(ts[0] - tv[3])) / cps);
32219  }
32220 
32221  if (b->metric) { // -m
32222  m.interpolatemeshsize();
32223 
32224  ts[1] = clock();
32225 
32226  if (!b->quiet) {
32227  printf("Size interpolating seconds: %g\n",((REAL)(ts[1]-ts[0])) / cps);
32228  }
32229  }
32230  }
32231 
32232  tv[4] = clock();
32233 
32234  if (b->plc && !b->refine) { // -p
32235  if (b->nobisect) { // -Y
32236  m.recoverboundary(ts[0]);
32237  } else {
32238  m.constraineddelaunay(ts[0]);
32239  }
32240 
32241  ts[1] = clock();
32242 
32243  if (!b->quiet) {
32244  if (b->nobisect) {
32245  printf("Boundary recovery ");
32246  } else {
32247  printf("Constrained Delaunay ");
32248  }
32249  printf("seconds: %g\n", ((REAL)(ts[1] - tv[4])) / cps);
32250  if (b->verbose) {
32251  printf(" Segment recovery seconds: %g\n",((REAL)(ts[0]-tv[4]))/ cps);
32252  printf(" Facet recovery seconds: %g\n", ((REAL)(ts[1]-ts[0])) / cps);
32253  }
32254  }
32255 
32256  m.carveholes();
32257 
32258  ts[2] = clock();
32259 
32260  if (!b->quiet) {
32261  printf("Exterior tets removal seconds: %g\n",((REAL)(ts[2]-ts[1]))/cps);
32262  }
32263 
32264  if (b->nobisect) { // -Y
32265  if (m.subvertstack->objects > 0l) {
32266  m.suppresssteinerpoints();
32267 
32268  ts[3] = clock();
32269 
32270  if (!b->quiet) {
32271  printf("Steiner suppression seconds: %g\n",
32272  ((REAL)(ts[3]-ts[2]))/cps);
32273  }
32274  }
32275  }
32276  }
32277 
32278  tv[5] = clock();
32279 
32280  if (b->coarsen) { // -R
32281  m.meshcoarsening();
32282  }
32283 
32284  tv[6] = clock();
32285 
32286  if (!b->quiet) {
32287  if (b->coarsen) {
32288  printf("Mesh coarsening seconds: %g\n", ((REAL)(tv[6] - tv[5])) / cps);
32289  }
32290  }
32291 
32292  if ((b->plc && b->nobisect) || b->coarsen) {
32293  m.recoverdelaunay();
32294  }
32295 
32296  tv[7] = clock();
32297 
32298  if (!b->quiet) {
32299  if ((b->plc && b->nobisect) || b->coarsen) {
32300  printf("Delaunay recovery seconds: %g\n", ((REAL)(tv[7] - tv[6]))/cps);
32301  }
32302  }
32303 
32304  if ((b->plc || b->refine) && b->insertaddpoints) { // -i
32305  if ((addin != NULL) && (addin->numberofpoints > 0)) {
32306  m.insertconstrainedpoints(addin);
32307  }
32308  }
32309 
32310  tv[8] = clock();
32311 
32312  if (!b->quiet) {
32313  if ((b->plc || b->refine) && b->insertaddpoints) { // -i
32314  if ((addin != NULL) && (addin->numberofpoints > 0)) {
32315  printf("Constrained points seconds: %g\n", ((REAL)(tv[8]-tv[7]))/cps);
32316  }
32317  }
32318  }
32319 
32320  if (b->quality) {
32321  m.delaunayrefinement();
32322  }
32323 
32324  tv[9] = clock();
32325 
32326  if (!b->quiet) {
32327  if (b->quality) {
32328  printf("Refinement seconds: %g\n", ((REAL)(tv[9] - tv[8])) / cps);
32329  }
32330  }
32331 
32332  if ((b->plc || b->refine) && (b->optlevel > 0)) {
32333  m.optimizemesh();
32334  }
32335 
32336  tv[10] = clock();
32337 
32338  if (!b->quiet) {
32339  if ((b->plc || b->refine) && (b->optlevel > 0)) {
32340  printf("Optimization seconds: %g\n", ((REAL)(tv[10] - tv[9])) / cps);
32341  }
32342  }
32343 
32344 
32345  if (!b->nojettison && ((m.dupverts > 0) || (m.unuverts > 0)
32346  || (b->refine && (in->numberofcorners == 10)))) {
32347  m.jettisonnodes();
32348  }
32349 
32350  if ((b->order == 2) && !b->convex) {
32351  m.highorder();
32352  }
32353 
32354  if (!b->quiet) {
32355  printf("\n");
32356  }
32357 
32358  if (out != (tetgenio *) NULL) {
32359  out->firstnumber = in->firstnumber;
32360  out->mesh_dim = in->mesh_dim;
32361  }
32362 
32363  if (b->nonodewritten || b->noiterationnum) {
32364  if (!b->quiet) {
32365  printf("NOT writing a .node file.\n");
32366  }
32367  } else {
32368  m.outnodes(out);
32369  }
32370 
32371  if (b->noelewritten) {
32372  if (!b->quiet) {
32373  printf("NOT writing an .ele file.\n");
32374  }
32375  m.indexelements();
32376  } else {
32377  if (m.tetrahedrons->items > 0l) {
32378  m.outelements(out);
32379  }
32380  }
32381 
32382  if (b->nofacewritten) {
32383  if (!b->quiet) {
32384  printf("NOT writing an .face file.\n");
32385  }
32386  } else {
32387  if (b->facesout) {
32388  if (m.tetrahedrons->items > 0l) {
32389  m.outfaces(out); // Output all faces.
32390  }
32391  } else {
32392  if (b->plc || b->refine) {
32393  if (m.subfaces->items > 0l) {
32394  m.outsubfaces(out); // Output boundary faces.
32395  }
32396  } else {
32397  if (m.tetrahedrons->items > 0l) {
32398  m.outhullfaces(out); // Output convex hull faces.
32399  }
32400  }
32401  }
32402  }
32403 
32404 
32405  if (b->nofacewritten) {
32406  if (!b->quiet) {
32407  printf("NOT writing an .edge file.\n");
32408  }
32409  } else {
32410  if (b->edgesout) { // -e
32411  m.outedges(out); // output all mesh edges.
32412  } else {
32413  if (b->plc || b->refine) {
32414  m.outsubsegments(out); // output subsegments.
32415  }
32416  }
32417  }
32418 
32419  if ((b->plc || b->refine) && b->metric) { // -m
32420  m.outmetrics(out);
32421  }
32422 
32423  if (!out && b->plc &&
32424  ((b->object == tetgenbehavior::OFF) ||
32425  (b->object == tetgenbehavior::PLY) ||
32426  (b->object == tetgenbehavior::STL))) {
32427  m.outsmesh(b->outfilename);
32428  }
32429 
32430  if (!out && b->meditview) {
32431  m.outmesh2medit(b->outfilename);
32432  }
32433 
32434 
32435  if (b->vtkview) {
32436  m.outmesh2vtk(b->outfilename);
32437  }
32438 
32439  if (b->neighout) {
32440  m.outneighbors(out);
32441  }
32442 
32443  if (b->voroout) {
32444  m.outvoronoi(out);
32445  }
32446 
32447 
32448  tv[11] = clock();
32449 
32450  if (!b->quiet) {
32451  printf("\nOutput seconds: %g\n", ((REAL)(tv[11] - tv[10])) / cps);
32452  printf("Total running seconds: %g\n", ((REAL)(tv[11] - tv[0])) / cps);
32453  }
32454 
32455  if (b->docheck) {
32456  m.checkmesh(0);
32457  if (b->plc || b->refine) {
32458  m.checkshells();
32459  m.checksegments();
32460  }
32461  if (b->docheck > 1) {
32462  m.checkdelaunay();
32463  }
32464  }
32465 
32466  if (!b->quiet) {
32467  m.statistics();
32468  }
32469  return mptr;
32470 }
32471 
32472 #ifndef TETLIBRARY
32473 
32475 // //
32476 // main() The command line interface of TetGen. //
32477 // //
32479 
32480 int main(int argc, char *argv[])
32481 
32482 #else // with TETLIBRARY
32483 
32485 // //
32486 // tetrahedralize() The library interface of TetGen. //
32487 // //
32489 
32490 tetgenmesh* tetrahedralize(const char *switches, tetgenio *in, tetgenio *out,
32491  tetgenio *addin, tetgenio *bgmin)
32492 
32493 #endif // not TETLIBRARY
32494 
32495 {
32496  tetgenbehavior b;
32497  tetgenmesh* mptr;
32498 
32499 #ifndef TETLIBRARY
32500 
32501  tetgenio in, addin, bgmin;
32502 
32503  if (!b.parse_commandline(argc, argv)) {
32504  terminatetetgen(NULL, 10);
32505  }
32506 
32507  // Read input files.
32508  if (b.refine) { // -r
32509  if (!in.load_tetmesh(b.infilename, (int) b.object)) {
32510  terminatetetgen(NULL, 10);
32511  }
32512  } else { // -p
32513  if (!in.load_plc(b.infilename, (int) b.object)) {
32514  terminatetetgen(NULL, 10);
32515  }
32516  }
32517  if (b.insertaddpoints) { // -i
32518  // Try to read a .a.node file.
32519  addin.load_node(b.addinfilename);
32520  }
32521  if (b.metric) { // -m
32522  // Try to read a background mesh in files .b.node, .b.ele.
32523  bgmin.load_tetmesh(b.bgmeshfilename, (int) b.object);
32524  }
32525 
32526  tetrahedralize(&b, &in, NULL, &addin, &bgmin);
32527 
32528  return 0;
32529 
32530 #else // with TETLIBRARY
32531 
32532  if (!b.parse_commandline(switches)) {
32533  terminatetetgen(NULL, 10);
32534  }
32535  mptr=tetrahedralize(&b, in, out, addin, bgmin);
32536  return mptr;
32537  // return;
32538 #endif // not TETLIBRARY
32539 }
32540 
32544